New properties for GObject
The existing property machinery for GObject is inefficient in various ways:
- GValue boxing and unboxing all over the place
- data is copied and freed
- locks are held
- even
va_list
paths end up into GValue, though we already know the final type
- entry points duplication
- massive
switch
inside GObject implementations for set and get - the
set_property()
andget_property()
code ends up calling into public API - double the validation, double the fun
-
g_object_set()
ends up notifying even without state change, unless the class explicitly opts out
- massive
-
GParamSpec
- weird API full of special cases
- does value validation separately from the GObject instance that installed the property
- value validation is separate from C types, and always explicit instead of being tied to the type itself (e.g.
uint8
needs auint + [0, 255]
GParamSpec)
-
GParamSpecPool
- singleton instance shared by all classes
- lock ALL the things
- run time introspection is expensive
- decoupled from GObject
- properties installed at class initialization requires creating classes
- bad for GObject introspection
- bad for documentation
- real library code needs to run, instead of simply using the type system
- side effects (open display server connections; network; type instantiation; locks)
- properties on interfaces require playing games with overrides, instead of tying a property to a set/get pair of virtual functions on the interface itself, to be overridden by implementations
Issue #408 (closed) outlined a new API for declaring GObject properties that dealt with validation, value boxing and unboxing, and added automatic generation of accessors to reduce duplication.
Unfortunately it's still missing a solution to avoid a costly property metaclass look up, and it got stuck there. Over the years, we identified a way forward to eliminate the global GParamSpec
pool and replace it with per-class GProperty
pointers, stored in the class private data structure using a constant offset. This would turn property look up into a cheaper operation than the current implementation.
Blockers
The missing pieces to land this work are:
-
ensure that private data for a GTypeClass
is allocated in the same way as the private data for aGTypeInstance
, and can be retrieved via pointer arithmetic -
every time a new property is installed on a class, it gets installed into the private data for the class -
property accessors generator macros can use the property id and the class private offset to access the GProperty
instance from an instance pointer
Issues
- ideally, we'd really like to have all the property metadata known by the type we register a
GType
; this would allow us to store the property metadata at a known offset from the start of the class pointer; in practice, this may not really possible because of mixed old-style/new-style inheritance hierarchies. We will need to create a per-class storage pointer to the actual property metaclass storage. New style classes could make it easier by declaring the number and type of properties to be created at type registration time, while old-style classes without properties would pay at most asizeof(void*)
cost in storage.
Edited by Emmanuele Bassi