I guess a lot of you, kind readers, are pretty well-acquainted with the current idiomatic way to write a GObject type. it’s the usual boilerplate, plus or minus a bunch of macros:
// header
typedef struct _MyObject MyObject;
typedef struct _MyObjectPrivate MyObjectPrivate;
typedef struct _MyObjectClass MyObjectClass;
struct _MyObject {
GObject parent_instance;
MyObjectPrivate *priv;
};
struct _MyObjectClass {
GObjectClass parent_class;
};
GType my_object_get_type (void);
// source
struct _MyObjectPrivate
{
int foo;
};
G_DEFINE_TYPE (MyObject, my_object, G_TYPE_OBJECT)
static void
my_object_class_init (MyObjectClass *klass)
{
g_type_class_add_private (klass, sizeof (MyObjectPrivate));
}
static void
my_object_init (MyObject *self)
{
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
my_object_get_type (),
MyObjectPrivate);
self->priv->foo = 42;
}
boring stuff that everyone had to remember ((or commit to a script to autogenerate it)). the last big change in the way people write GObject happened 10 years ago, and it was the addition of per-instance private data. it seems to me like a good way to celebrate that occasion to change this stuff all over again. ;-)
at the latest GTK+ hackfest, Alex and Ryan had a very evil, and very clever idea to solve a problem in how the per-instance private data is laid out in memory. before that, the layout was:
[[[GTypeInstance] GObject] TypeA] TypeB] [TypeAPrivate] [TypeBPrivate]
as you can see, the offset of the private data for each type changes depending at which point in the class hierarchy initialization we are, and can only be determined once the whole class hierarchy has been initialized. this makes retrieving the pointer of the private data a pretty hard problem; one way to solve it is storing the private pointer when we initialize the instance, and we spare ourselves from type checks and traversals. the main problem is that, in order to get to the private data faster, we need to rely on a specific layout of the instance structure, something that is not really nice if we want to have generic accessors to private data ((say, for instance, if we’re re-implementing the way properties are handled in GObject)). for that, it would be really cool if we could only have offsets to through to G_STRUCT_MEMBER()
.
well, it turns out that if you’re doing memory allocations for the instance you can overallocate a bit, and return a pointer in the middle of the memory you allocated. you can actually allocate the whole private data in a decent layout, and only deal with offsets safely — after all, the type information will store all the offsets for safe access. so, here’s the new layout in memory of a GObject ((well, of any GTypeInstance
, really)):
[TypeBPrivate] [TypeAPrivate] [[[[GTypeInstance] GObject] TypeA] TypeB]
that’s neat, isn’t it? now all private data can be accessed simply through offsets, and accessing it should be just as fast as a private pointer.
I can already see people using Valgrind preparing torches and pitchforks — but fear not, my fellow developers: GLib now detects if you’re running under Valgrind, and it will communicate with it ((yes, you can do that, and it’s an impressive amount of crack, luckily for us hidden behind the valgrind.h
header provided by the Valgrind folks)) about this new memory layout, as well as keeping a pointer to the beginning of the allocated region, so that you won’t get false positives in your report.
this was the state at the end of the hackfest. on top of that, I decided to contribute a bunch of “syntactic sugar” ((i.e. pre-processor macros)) to cut down the amount of lines and things to remember ((the port of GIO to the new macros lost around 900 lines)), as well as providing a good base towards making GProperty work better, and with fewer headaches.
so, here’s how you create a new GObject type in the Brave New World:
// header
typedef struct _MyObject MyObject;
typedef struct _MyObjectClass MyObjectClass;
struct _MyObject {
GObject parent_instance;
};
struct _MyObjectClass {
GObjectClass parent_class;
};
GType my_object_get_type (void);
// source
typedef struct {
int foo;
} MyObjectPrivate;
G_DEFINE_TYPE_WITH_PRIVATE (MyObject, my_object, G_TYPE_OBJECT)
static void
my_object_class_init (MyObjectClass *klass)
{
}
static void
my_object_init (MyObject *self)
{
MyObjectPrivate *priv = my_object_get_instance_private (self);
priv->foo = 42;
}
the my_object_get_instance_private()
function is generated by G_DEFINE_TYPE
, so you can forget about G_TYPE_INSTANCE_GET_PRIVATE
and all that jazz. also, no more g_type_class_add_private()
— one less thing to remember is one less thing to screw up. you can still store the private pointer in your instance structure — and if you care about ABI compatibility, you really should — but for new code it’s not necessary. you can finally hide the private data structure inside your source code, instead of having the typedef in your header, sitting there, taunting you. finally, everything is just as fast as it was, as well as backward compatible.
stay tuned for the next blog post, because it’ll finally be about GProperty…