Everyone, Ok, I put together a patch to provide opaque enumerations for glib. This is intended to look like java.util.Enumeration, because I've found that functionality excellent. I sent it to Tim, who recommends that I get discussion here. Why this, when I can just return a GList* from a function? I find that returning lists is non-trivially obvious wrt memory handling. We've already had a long discussion on whether to return values by reference (don't free/change) or by copy (store in temp_var and free() yourself). This doesn't solve that problem. But what of a _list_ of values? Say you have a structure struct Foo { ... GList *children; ... }; and a function foo_get_children(struct Foo *foo); what does this function do? It can do any of these: return(foo->children) /* internal GList*, caller better not modify _anything_ */ return(foo->children) /* internal GList*, caller better not modify the GList, but express permission is granted to modify list->data elements */ return(g_list_copy(foo->children)) /* the list->data elements are *still* internal. Here the caller *must* free() the returned list, but must explicitly copy any ->data elements they wish to modify, and they had better not modify the originals */ return(foo_deep_copy(foo->children)) /* everything is a copy, and the caller *must* know to free() _everything_. What a pain! */ Of course, documentation can specify on what terms the returned GList* must be handled. But most of the GTK+/GNOME documentation that I've seen doesn't. Instead, you just have to read the source and see. And heaven forbid the library change it on you (of course). With an Enumeration, the actual mechanism of how the items are listed is hidden behind an opaque API. There might be an internal list, a copy of the list, or even a dynamicly generated next element. It doesn't matter. The caller just knows how to get it. The opaque API generating the enumeration handles the internals. from the caller's perspective: GEnumeration *foo_list = foo_enumerate_children(foo); while (g_enumeration_has_more(foo_list)) { FooChild *child = (FooChild *)g_enumeration_get_next(foo_list); do_something(child); } g_enumeration_free(foo_list); Now, while there isn't much more/less code than a GList*, the caller has no knowledge of how the Foo object is handling the enumeration, and has no _need_ to. Any every access to an enumerated entity in the Foo object's API looks the same, no matter how the internal of the Foo object is implementing each. So when the caller just wants a list of things, it is easy, consistent, and there is no question of the enumeration's memory characterisics. I'm not advocating replacement of all GList* return values. In an internal API (within a module, say) there is no reason to hide the characteristics, because it is a self-contained unit. But when a library is providing an opaque API, I think this is a win. So when evaluating it, please don't say "Ahh, we have GList", instead ask "Are there cases where this is clearer than GList?" The attached patch contains the GEnumeration code, a quick GEnumeration addition to GHashTable as an example, a go at RDP sgml, and all the proper testglib examples, including a dynamically generated enumeration. Questions, comments, improvements to gtk-devel. Flames and studlyCaps to me privately. Joel -- "But all my words come back to me In shades of mediocrity. Like emptiness in harmony I need someone to comfort me." http://www.jlbec.org/ jlbec evilplan org
--- Begin Message ---
- From: Joel Becker <jlbec evilplan org>
- To: Tim Janik <timj gtk org>
- Subject: Enumeration patch
- Date: Sat, 14 Oct 2000 08:24:50 +0100
Tim, Hot on the heels of my recent query, I've cooked up a quick patch to add opaque Enumerations to glib, ala java.util.Enumeration. Since I personally find the "do I free this returned GList?" confusion a headache, I like this interface better. It also allows the flexibitiy of dynamically iterated enumerations (see the patches to testglib). Included is the code to build in HEAD, testglib tests, and a first shot at RDP SGML. Note that diff(1) put the SGML at the front of the diff, so some scrolling is required. For yuks I also added a g_hash_table_enumerate_keys() quickie to example the idea. Oh, and while I hope I did the coding style ok, I'd really prefer a publically available .indent.pro. Comments, hints, allegations, flames. If you think it a bad idea, fine. If not, let me know and I'll hit gtk-devel with it. Joel -- Life's Little Instruction Book #347 "Never waste the oppourtunity to tell someone you love them." http://www.jlbec.org/ jlbec evilplan orgAttachment: genumeration.diff.gz
Description: Binary data
--- End Message ---