g_object_{new,set,get} vs. class-specific function

Mark Doliner mark at kingant.net
Sun May 20 13:04:22 EDT 2007


On Sun, 20 May 2007 08:16:25 -0500, Gabriel Schulhof wrote
> Hi, Richard!
> 
> You asked me why I prefer using GObject properties rather than
> class-specific accessors and constructors. A bit of an essay follows,
>  so please feel free to ignore it and instruct me to use the class-specific
> functions in Pidgin :o)
> 
> I have found several reasons:
> 
> - Using g_object_new instead of the class-specific constructors is more
> flexible, primarily because you're not restricted to the constructors
> available for the given type. For example:
> 
> gtk_window_new (GTK_WINDOW_TOPLEVEL);
> 
> Here, the argument will be GTK_WINDOW_TOPLEVEL 99.99% of the time. This
> also happens to be the default value of the "type" property, so it
> shouldn't need to be specified. OTOH, because of this lone 
> constructor, you need to make additional calls to properly configure 
> the window: gtk_window_set_title gtk_window_set_resizable
gtk_container_set_border_width
> gtk_window_set_default_size
> gtk_window_set_role
> With g_object_new, you could create and configure your window in one
> call:
> g_object_new(GTK_TYPE_WINDOW,
>   "title",         _("My Window"),    "resizable",      FALSE,
>   "border-width",  PIDGIN_HIG_BORDER, "role",           "demo",
>   "default-width", 320,               "default-height", 240, NULL) ;
> 
> And, even if that doesn't float your boat, you can at least replace the
> useless GTK_WINDOW_TOPLEVEL with, say, the more useful "title":
> -gtk_window_new(GTK_WINDOW_TOPLEVEL);
> +g_object_new(GTK_TYPE_WINDOW, "title", _("My Window"), NULL);
> 
> Another example:
> 
> label = gtk_label_new("Some Really Long Text");
> gtk_widget_show(label);
> gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
> gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
> gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0);
> 
> vs.
> 
> g_object_new(GTK_TYPE_LABEL,
>   "visible", TRUE, "label",   _("Some Really Long Text"),
>   "wrap",    TRUE, "justify", GTK_JUSTIFY_LEFT,
>   "xalign",  0.0,  "yalign",  0.0, NULL);
> 
> This particular example illustrates a sequence that is present for
> almost all child widgets ever created:
> 
> new_widget = gtk_some_widget_new();
> gtk_widget_show(new_widget);
> 
> If you do nothing else, you could at least replace the above two 
> lines with new_widget = g_object_new (GTK_TYPE_SOME_WIDGET,
>  "visible", TRUE, NULL) and save a line of code for each child 
> widget created. For constructors with more than 0 parameters, you 
> can still specify those parameters on the one line of code that 
> creates and now shows the widget.
> 
> - Another benefit of g_object_new is that you can free yourself from
> having to track uninteresting widgets. For example:
> 
> GtkWidget *label = NULL, *important_entry = NULL;
> 
> label = gtk_label_new("Temperature:");
> gtk_widget_show(label);
> gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_RIGHT);
> gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
> gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, TRUE, 0) ;
> 
> important_entry = gtk_entry_new() ;
> gtk_widget_show(important_entry);
> gtk_box_pack_start(GTK_BOX(hbox), important_entry, TRUE, TRUE, 0);
> 
> vs.
> 
> GtkWidget *important_entry = NULL;
> 
> gtk_container_add_with_properties (GTK_CONTAINER (hbox),
>   g_object_new (GTK_TYPE_LABEL, "visible", TRUE, "justify",
> GTK_JUSTIFY_RIGHT, "xalign", 1.0, "yalign", 0.5, NULL),
>   "expand", FALSE, NULL);
> 
> gtk_container_add (GTK_CONTAINER (hbox),
>   important_entry = g_object_new (GTK_TYPE_ENTRY, "visible", TRUE,
> NULL));
> 
> This sequence brings up another point:
> 
> - With properties, you are not forced to specify values that should 
> be kept default
> 
> Your example:
> gtk_vbox_new (gboolean homogeneous, gint spacing);
> 
> Why should I be forced to specify a spacing whenever I create a VBox?
> Keeping the default would probably eliminate a lot of hardcoded values.
> In fact (and with a little more blue-sky thinking) it would allow 
> one to set a system-wide default value that all apps would all-of-a-sudden
> reflect. Kinda like style properties, actually, which (I speculate)
> would then become just like normal properties.
> 
> Side note: "homogeneous" is also FALSE by default, and specified as
> "FALSE" 99.99% of the time when creating a vbox or and hbox. So, 
> again, completely useless. g_object_new (GTK_TYPE_VBOX, "visible", 
> TRUE, NULL) would be far more useful.
> 
> In a similar vein, specifying the padding when calling
> gtk_box_pack_start is also a source of hardcoded values. So, why have
> it? Just use gtk_container_add_with_properties and specify only those
> child properties whose default values are not what you want.
> 
> - Using g_object_{get,set} allows you to become a little more
> object-type-agnostic. Consider, for example, an object class that
> "sports" the "active" property. It could be a GtkToggleButton or a
> GtkToggleToolButton. If we were to always use g_object_get (G_OBJECT
> (widget), "active", &active, NULL); instead of
> gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)), we could
> change the type of the widget (and therefore our UI) without having 
> to touch those parts of the code where we retrieve the "active" 
> property, by virtue of the fact that different widget classes all 
> implement this "active" property. I have experienced the 
> GtkToggleButton/GtkToggleToolButton scenario when I introduced a 
> GtkToolbar into one of my apps, and I had to hunt the code for calls 
> to gtk_toggle_button_{get,set}_active (GTK_TOGGLE_BUTTON
> (the_toggle_button)) and change it to gtk_toggle_tool_button_{get,
> set}_active (GTK_TOGGLE_TOOL_BUTTON
> (the_toggle_button))
> 
> Of course, if you use g_object_{get,set}, you can also connect a signal
> handler to multiple different object types, as long as they all have 
> the property your signal handler is interested in.
> 
> Gabriel

My biggest argument against using g_object_new() is that you lose a lot of
compile-time checking.  What happens if you accidentally pass in "justlfy"
instead of "justify" when creating a label?

-Mark




More information about the Devel mailing list