A GObject
is a GTypeInstance
.
GTypeInstance
has its own system of constructing and initialising instances. It’s very simple: you call g_type_create_instance()
. GType
allocates the necessary memory for the instance and then calls each _init()
function, from the base type to the most derived type. There are no properties here.
But we want to create a GObject
. That’s always done with g_object_new()
. The first thing that g_object_new()
does is to sort the properties that you pass to it into construct and non-construct properties. The list of construct properties is in the order that you passed them. Added to this list (at the end) are any construct properties that you did not pass to g_object_new()
, with their default values.
g_object_new()
then calls the constructor()
virtual function for your class with the list of construct properties. This is usually the internal function g_object_construct
, but you can override it (but you must chain up). This is the first place that you can possibly intercept construction of a GObject
.
calls
g_object_construct()g_type_create_instance()
which results in all the _init()
functions being called (as described above). It then sets the construct properties in the order that they were given to g_object_new()
(with the default values at the end). This results in you getting a lot of _set_property()
calls.
Then it returns. Your constructor()
override gets another chance to do things here if you want.
Back in g_object_new()
, the constructed()
virtual function is called to let you know that we’re (almost) done. If you implement this then you need to chain up.
Finally, the non-construct properties that you passed to g_object_new()
are set in the order passed. More _set_property()
calls for you.
Then g_object_new()
returns. A lot of people take this chance to do some extra things in their C API constructor function (but binding authors and those who want to subclass you may get angry if you do that).
The long and the short of it is that there are a bunch of different parts of your code that you can hook into to do various things during object construction (in order of when they are called):
constructor()
override (before chainup) of each class from most derived to baseGType
_init()
function of each class from base to most derived_set_property()
function for each construct property given tog_object_new()
, in order_set_property()
function for each construct property not given tog_object_new()
constructor()
override (after chainup) of each class from base to most derivedconstructed()
override (before chainup) of each class from most derived to baseconstructed()
override (after chainup) from each class from base to most derived_set_property()
for the remaining properties passed tog_object_new()
- whatever code you do in your
_new()
function afterg_object_new()
There are a few conclusion to draw from all of this that a lot of people first using GObject
are often surprised about:
- you do not have access to values of properties passed to
g_object_new()
(even construct properties) from yourGType
_init()
function. You should think of_init()
as doing the work necessary to make it safe for_set_property()
calls to begin happening to your object. _init()
is not a great place to set values for properties on your parent class. If those properties are construct properties then they will later be reset to their default values by the later call to_set_property()
(even if the property was not passed tog_object_new()
). Consider usingconstructed()
for this instead.- none-the-less, as a potential parent class, you should expect that your subclasses may attempt to set non-construct properties from their
GType
_init()
functions which means that you may end up seeing_set_property()
for non-construct properties before you see it for construct properties (delivered byGObject
in the usual way).
And a couple more notes and general advice:
- since
_init()
doesn’t have access to any properties, you should limit it to simple always-the-same initialisation tasks such as setting up your->priv
pointer or allocating internal arrays and hashtables or so on. - overriding
constructor()
is difficult and ugly. Attempting to manipulate the property array that gets passed through is even more complicated. You almost certainly don’t want to do this unless you are doing something exceptionally evil. constructed()
is easy to override and at this point all your construct properties have been set. This is a good place to do the ‘heavy lifting’ of initialising your object that is dependent on construct properties. This is whereGSettings
opens its schemas, for example.constructed()
is somewhat less useful than it would have been if it was called after all properties (not just construct-only ones) were set, but we probably can’t change it at this point.
Great explanations. Shouldn’t this be included in developer.gnome.org?
You should copy and paste this into the GObject API docs. Srsly.
What’s there now doesn’t really reflect current best practices:
http://developer.gnome.org/gobject/unstable/chapter-gobject.html#gobject-instantiation
You touched on this but it should be made more explicit:
If you want your class to instantiate right in binding languages and tools such as Glade don’t put any extra code in your _new convinience constuctors. Everything that needs to be setup should happen in your virtual methods or in set_property. Failure to do so means a simple call to g_object_new may not construct your object correctly.
One thing that I’ve always found mysterious about GObject is why non-construct properties exist at all. Why would you ever *not* want a default value to be set? Why would you ever *not* want the guarantee that the property is ready to use by the time you get to constructed()?
Does anybody know the original motivation behind non-construct properties, or in what circumstances they should be used?
i actually find the set-to-default behaviour to be somewhat obnoxious.
the original patch for constructed() set the non-construct properties before the call, but it got shuffled around a bit before it got committed and we landed at the current suboptimal behaviour instead.
I forgot to say, the guide is excellent, thank you very much :-)
Since it’s not ideal to do so in _init(), what’s the recommended way for subclasses to set different default property values from their parents? constructed() is too late, and trying to do so in constructor() in the middle of the chain-up sequence is just horrible.
It’s easy to do by passing the new defaults to g_object_new() in the subclass’s _new() function, but that’s not ideal either…
Thanks for the guide… :-)
What I however keep wondering is how I can model the failure of object instaciation in GObject. A case that can happen especially when providing bindings to other libs…
Could I e.g. return NULL from the construtor or can one of the properties be a GError** ?
Currently I have my own _new(GError**), but this does not really feel correct…
If you have an answer or best practice for such cases, that would be great !
hi Andreas,
GObject construction never fails. Period.
g_object_new()
will always return a non-NULL pointer to you.That said, we have a very strong convention for
your_obj_new()
failing and an interface with conventions for this:GInitable
. In short, you create the object withg_object_new()
(always works) and then you call a failable initialiser on it (part of theGInitable
interface). If that fails, then you returnNULL
from theyour_obj_new()
function (usually with aGError*
with the reason). The reason we go about it this way is because we want you to be able to subclass objects with failable initialisation and that wouldn’t work if you just put the initialisation in theyour_obj_new()
functions. See http://developer.gnome.org/gio/stable/GInitable.html for the documentation.There is also
GAsyncInitable
as the convention for dealing with asynchronous (and failable) initialisation. It turns out that the cases that fail are often quite similar to the cases where you want asynchronous IO (ie: loading files, connecting sockets, etc).Thanks a lot for that clearification… Was hard to work out of the general tutorials… :-)
Though I see the heavy use in GIO, I don’t understand, why GInitiable is defined in GIO… My guess would have been, that this may be interessting in GObject itself…
What I also don’t really see is how to sensefully work around the name-conflict between the GInitiable_init and the init of the object subclassed from GInitiable…
I guess it will require:
my_object_init (): regular init stuff for my Object
my_object_initiable_init (): the initiable virtual function implementation for my Object…
with initiable_iface->init = my_class_initiable_init in the constructor of my Object…
Or do I miss something here ?
That’s pretty much correct, with the minor detail that the vtable setup goes in the interface init function (which is separate from your normal class init function). Look up
G_DEFINE_TYPE_WITH_CODE()
andG_IMPLEMENT_INTERFACE()
, btw, if you didn’t know about them already.