On Fri, 17 Apr 2009, Cody Russell wrote:
This is rather old, but it never came up again after this so I'd like to see what thoughts are about how to implement this in C. It was in 2.13 but removed before 2.14 because of disagreement, but I can't find any public record of the disagreement in gtk-devel-list. Can anyone comment on what was not liked, or how a better implementation could be made?
There was a lengthy #gtk+ discussion about this that could be dug out of the archives. But I'll better summarize the original API motivation here: GtkAllocation gtk_widget_get_allocation (GtkWidget *widget); Structures like GtkAllocation/GtkRequisition are very similar to (newer) C standards constructs like struct Complex { double real, imag; }, i.e. a fundamental compound, fully exposed to the user. Consequently they shouldn't be sealed, but be directly used and manipulatable by the user. An important part of what makes dealing with Gtk+ in C so cumbersome is the variations and inconvenient definitions in our getter APIs. Many force two lines instead of one-liners for accesing a simple value if compound structures are involved. This is unneccessarily so, as long as returned structs doesn't get too big, passing by value is convenient, and acceptable performance wise (and definitely portable C as well). FWIW, returning a GtkAllocation is exactly as many bytes as returning a double. Here's an extreme case of getter inconvenience in Gdk/Gtk+: void gdk_window_set_user_data (GdkWindow *window, gpointer user_data); void gdk_window_get_user_data (GdkWindow *window, gpointer *data); The choosen API might look most symmetric, but the getter is utterly cumbersome to use, currently it forces us to: gpointer helper_variable; // declare this lines away at start of code block gdk_window_get_user_data (window, &helper_variable); // getter foo = helper_variable; // use Instead of what could have simply been: foo = gdk_window_get_user_data (window); // getter, use, no helper For a central API like Gtk+s which is very widely used, 1 or 2 additional user code lines forced by our API choices can make a huge difference if its needed in many places. That is the case here, lots of code portions that currently do widget->allocation.{member} could either be changed to: gtk_widget_get_allocation (widget).{member} in the future, or to multiple lines of code, possibly spread out a fair bit, because a helper variable needs to be declared. And while returning a GtkAllocation* from gtk_widget_get_allocation() would technically be feasible for the immediate current migration, in the future we might want to hand out coordinates different from the actual widget->allocation (e.g. handing out the allocation assigned by a parent and not the possibly "adjusted" one stored in the child like GtkSpinButton does it). This has basically the same problem as const char*, either we hand out a pointer to internals and in the absence of GC force ourselves into keeping certain structure members around forever, or we hand out a copy and force the caller into freeing (forcing 3 instead of 1 lines of caller code). To sum up our getter options: a) /* force adding lots of helper variables into user code */ void gtk_widget_get_allocation (GtkWidget *widget, GtkAllocation *allocation); b) /* convenient access, no garbage collection problem */ GtkAllocation gtk_widget_get_allocation (GtkWidget *widget); c) /* tie ourselves into always keeping the handed out GtkAllocation * allocated in the widget, which can be different from the * actual widget->allocation. */ const GtkAllocation* gtk_widget_get_allocation (GtkWidget *widget); d) /* force caller to free returned allocation, most often forces * an extra GtkAllocation *helper; variable. */ GtkAllocation* /*freeme*/ gtk_widget_get_allocation (GtkWidget *widget); Here, (c) is the worst as it preserves part of our current API problem we intended to fix with GSEAL(). Now, (a) is what's often used in Gtk+ currently, but forces user code into explicitely adding helper variables. Together with non-C99 compliance, it forces *two* simultaneous code changes many lines *apart*. Currently (d) is what we do for strings, most often an additional helper variable like in (a) is needed here as well, to allow access and freeing, e.g. GtkAllocation *a; a = gtk_widget_get_allocation (widget); foo = a->{member}; g_free (a); So, given the technical problem of (c), and then the pain and error- proneness inflicted on users by (a) and (d), I highly prefer (b). At first sight, it might seem a bit inefficient over the other variants, but upon closer inspection (sizeofs) and given resonable compiler optimizations, it's not doing more structure copies than (a) or (d), and doesn't come with heap modification overhead like (d). Using register returns, it could even turn out more efficient than (a) for some optimization combinations, but apart from (d), possible speed differences around these API choices are really negligible. On 32bit systems (c) does lesser copying (not on 64bit), but then has a major technical problem so can't be used anyway. So in the interest of not making our C API users life even harder, by forcing the writing of useless extra lines in many places and thus creating more code that's prone to errors, it'd be best for Gtk+ to provide convenient accessors in the style of (b) in the future. Keeping current uses just because we're used to them is going to prevent change for the better. And introducing a new API style will create "inconsistencies" only temporarily, fixing all getters over to the new style and cleaning old cruft gets rid of the "inconsistency" argument as well.
/ Cody
Thanks for picking this up again Cody. I think I've brought up everything useful around this controversy at this point, and sincerely hope the community will come to senses for its own convenience around this issue. FWIW, this is not a vendetta out of *personal* interests of mine ;) I usually write GCC code if coding in C these days, and that allows me to work around such legacy APIs with e.g.: #define widget_get_allocation(w) \ ({ GtkAllocation a; gtk_widget_get_allocation (w, &a); a; }) I'd just hope Gtk+ application writers out there didn't have to introduce so much convenience glue. --- ciaoTJ _______________________________________________ gtk-devel-list mailing list gtk-devel-list@gnome.org http://mail.gnome.org/mailman/listinfo/gtk-devel-list