Changing quickly between a final and derivable GObject class

When doing code refactorings, it is sometimes desirable to change between a final and derivable GObject class. So it is important that that operation can be done quickly, as every other small refactorings that you usually do in your code.

In fact, when refactoring some code, sometimes you want to quickly try something to see if the result is better. But if a certain refactoring task takes a lot of manual and boring steps, (1) it’s not a pleasure to do it and (2) if the result (after other refactorings) is not what you want, you’ve lost your time.

To evolve in the right direction, a code needs to be easily modifiable.

With the convention to put GObject instance variables in the Private struct for derivable types, and in the object struct for final types, changing between the two is currently quite burdensome (because there is no tools to do it quickly):

/* For a final type */
my_object_get_foo (MyObject *object)
  return object->foo;

/* For a derivable type */
my_object_get_foo (MyObject *object)
  MyObjectPrivate *priv = my_object_get_instance_private (object);

  return priv->foo;

Maybe in a library like GTK+, changing between a final and derivable type is not a common operation. But in an application, it can be more common. For example when you want to move a class from an application to a library (it can be an internal or external library), one way to do it is to move the re-usable code in the library and keep the app-specific code in a subclass. So in that case, the class in the library needs to be derivable!

There is, though, another convention that can be used with GObject: always use a Private struct, even for final types.

But, calling my_object_get_instance_private() in each function is quite cumbersome… With the old convention to have a 'priv' field in the object struct to access the Private struct, you don’t have that problem. For example:

/* Old convention: have a 'priv' field in the object struct. */
my_object_get_foo (MyObject *object)
  return object->priv->foo;

Although for a library it’s better to not have the 'priv' field, I tend to prefer that latter code.

TL;DR: writing and refactoring GObject code in C can be quite painful, we need more tools. In the meantime, there can be a big difference just by following a different convention.

Edit: If you’ve read this blog post, you might think “just use Vala or Python or JavaScript! problem solved!”, but I still prefer the C language for GNOME development for reasons explained in this document. And to develop a library, the C language is the de facto language in GNOME.

6 thoughts on “Changing quickly between a final and derivable GObject class”

  1. With G_DECLARE_ macro you cannot use the self->priv->foo pattern anymore. What I do now is adding this at the top of the c file:

    #define priv ((MyObjectPrivate*)my_object_get_instance_private(self))

    So I can do priv->foo directly.

    1. I didn’t think about that, the code looks probably “lighter” like that.

      But if you have an old and big codebase that uses the self->priv->foo convention, converting every class to use G_DECLARE_ is a lot of manual work and IMO doesn’t really worth it. There are more important things to do, like, I don’t know, fixing some bugs.

      But nowadays we see people doing exactly that, converting big codebases to use G_DECLARE_. And people like me that want to contribute to the same codebase by making the code more re-usable…

      Anyway, there is a minor drawback with your trick to access the Private structure. In C, I like the fact that usually every type is known. In the examples I have given in the blog post, each time you know that ‘foo’ comes from MyObjectPrivate. With your example, it looks like ‘priv’ comes from nowhere (if you just look at the function), like in C++. With self->priv->foo, you know the type of self, so you can just follow the yellow bricks.

  2. I’m no expert in GObject, the GObjects I’ve written have almost all been GStreamer elements, but if you don’t want someone deriving from your class can’t you put the strict definition in the c file and omit it from the header file?

    My understanding is that it is still possible to use g_object_new to construct these objects.

Leave a Reply

Your email address will not be published. Required fields are marked *