Proposal: Default Constructors in GI



Hi All,

In an effort to cleanup the Python bindings, I have been auditing the plethora of overrides to see what can be removed [1]. There are a handful of cases where the binding machinery could handle things given more information from GI as opposed to binding overrides. Specifically, overridden methods like constructors (__new__ in Python).

The proposal is to add meta data attributes to various classes which describe what to use for default construction. This would be particularly useful in cases where g_object_new is invalid and may even crash (singletons and GBinding for example). These problems definitely threw me off when I first started learning GI and I have dealt with a number of related tickets since, hence this proposal. I attempted some analysis by following classes without public constructors [2] and created a tracking ticket for related issues [3].

The idea is to introduce two annotations for classes: "factory" and "constructor", either as first class annotations or as generic attribute annotations. The concept of a "factory" applies to object creation for an entire class hierarchy and requires a type as the first argument for dispatching. The "constructor" annotation can then override the factory for class specific creation where needed.

The primary usage of the factory annotation is to fix problems related to GInitiallyUnowned class hierarchies used with g_object_new (which is marked as transfer-full but may return a floating reference). Example annotation as follows:

/**
 * GObject:
 * Attributes: (meta.factory GObject.Object.new)
 **/

/**
 * GInitiallyUnowned:
 * Attributes: (meta.factory GObject.InitiallyUnowned.new)
 **/

This introduces a new factory function designed for GInitiallyUnowned and any sub-classes. g_initially_unowned_newv would wrap g_object_newv but with the return marked as transfer-none (or transfer-floating). This gives bindings the correct information to use g_object_ref_sink on the result. This would allow us to remove the special case hacks in bindings which use g_object_newv for generically creating all objects (checking if the class is GInitiallyUnowned or is floating and sinking accordingly). While the hacks really aren't such a big deal, this gives a concise way bindings should interpret GI and allow for purer GI bindings.

Default constructor annotations hint that the class should not use the factory, but instead use the specified class constructor (overrides the class hierarchies factory for this specific class):

/**
 * GVolumeMonitor:
 * ...
 * Attributes: (meta.constructor GObject.VolumeMonitor.get)
 *  ...or to not allow construction...
 * Attributes: (meta.constructor GObject.private_constructor_error)
 **/

Note that this must be restricted to the class it is called on (cannot be used for sub-classes). For this reason, it is important to distinguish the annotations for factory and constructor creation. For Python, standard object creation of Gio.VolumeMonitor() would then give back the singleton instance (the machinery will call "get"). Or as noted in the example, marking construction private which would give an error. private_constructor_error being a function which takes and fills out a GError resulting in an exception for interpreted languages. So in this case, calling Gio.VolumeMonitor() would raise an exception with something like: "direct creation of class is not allowed, please read the class documentation." This will help relieve support tickets.

Classes which have required constructor arguments but no way to specify this [4] can use a default constructor annotation with an explicit function that requires the arguments:

/**
 * GtkTreeModelFilter:
 * Attributes: (meta.constructor Gtk.TreeModelFilter.new)    ...requires child_model and root arguments...
 **/

Additional Thoughts:
* The names used for the attribute annotations are initial suggestions.
* I am a little biased towards using "Attributes:" as opposed to adding first class annotations because:
** It will be easier.
** Bindings don't have to rely on new GI API and can still work with older versions of GLIb/GTK+ as they always have.
* We should not add default constructor annotations to classes which are already working with g_object_new because it might break things. Only add constructor annotations to classes which are already broken or require overrides to dispatch to the appropriate constructor.

Feedback appreciated.
-Simon

[1] https://bugzilla.gnome.org/show_bug.cgi?id=705810
[2] https://wiki.gnome.org/PyGObject/Analysis/Bug675581
[3] https://bugzilla.gnome.org/showdependencytree.cgi?id=708060
[4] https://bugzilla.gnome.org/show_bug.cgi?id=649662




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]