GNOME Bugzilla – Bug 675648
Support explicitly required constructor parameters for objects
Last modified: 2013-08-29 21:15:18 UTC
An issue has come up with pygobject bindings where we cannot check required constructor parameters before attempting the creation of an object. The problem is with trying to create a GBinding object through g_object_newv. See:
The GBinding class marks a number of parameters as G_PARAM_CONSTRUCT_ONLY but the docs for this flag state the default will be used if these params are not passed in:
Specifically the source and target object will default to NULL causing g_binding_constructed to assert and cause python to segfault.
I propose an additional flag that GBinding could use to specify these construction params as required, something like G_PARAM_CONSTRUCT_REQUIRED. g_object_newv should then make sure params marked as required are passed in.
Additionally if GBinding is not intended as being creatable through g_object_new then G_TYPE_FLAG_INSTANTIATABLE should be removed from the types flags.
the only way to create a GBinding instance is to use the g_object_bind_property family of functions. GBinding has to be instantiatable, but it has to be created following a specific set of constraints - partially enforced through construct-only properties.
simply put: don't create GBinding instances yourself.
I figured as much. However, the knowledge that GBinding must be created through g_object_bind_property and that you should not use g_object_new directly is not programmatically knowable (to the best of my knowledge). To fix this in the pygobject we have to add a special case override for the GBinding object which then raises and attempts giving some useful information back to the programmer rather than a seg fault which is what it does now. I assume this special case would also need to occur in all other languages which generate bindings through introspection.
yes, it'll have to be done in all introspection-based bindings; we can probably add better documentation for GBinding, so that binding authors are aware of this. I'd gladly accept a patch for that.
Reopening, because this flag would be useful for things other than GBinding anyway. Eg, GFilterInputStream's base-stream property.
as I said in bug 675581, I'd consider any GParamSpec with G_PARAM_CONSTRUCT_ONLY a required constructor property by definition - given that GObject will implicitly make up a value (using the default one) if one is not explicitly passed.
there are cases when the default value is impossible to determine, and others where the default value is specified inside the GParamSpec itself; the former would be the case warranting extra annotations (i.e. not only providing a value is required by virtue of a construct-only GParamSpec, but also it's necessary to specify a value and not rely on the default). this extra annotation could very well be an introspection annotation instead of a GParamFlags enumeration value, given that we have limited expansion capabilities for that enumeration (see G_PARAM_MASK and G_PARAM_USER_SHIFT).
as far as I'm concerned, PyGObject should ensure that the __init__ gets passed all construct-only properties, if any are set, and not rely on the GParamSpec default value implicitly set by GObject.
(In reply to comment #5)
> as I said in bug 675581, I'd consider any GParamSpec with
> G_PARAM_CONSTRUCT_ONLY a required constructor property by definition - given
> that GObject will implicitly make up a value (using the default one) if one is
> not explicitly passed.
Yes, the intended meaning was "required to be specified by the caller". HAS_NO_DEFAULT if you prefer.
> this extra annotation could
> very well be an introspection annotation instead of a GParamFlags enumeration
> as far as I'm concerned, PyGObject should ensure that the __init__ gets passed
> all construct-only properties, if any are set, and not rely on the GParamSpec
> default value implicitly set by GObject.
"ensure" how? It can't infer the correct values itself. And making the caller explicitly specify values for all construct-only properties would be annoying. And would also mean that adding a new construct-only property would become an API break.
(And FTR, note that there are also construct-only GObject properties that *aren't* mandatory to specify. Eg, GTlsCertificate:issuer.)
(In reply to comment #6)
> > as far as I'm concerned, PyGObject should ensure that the __init__ gets passed
> > all construct-only properties, if any are set, and not rely on the GParamSpec
> > default value implicitly set by GObject.
> "ensure" how? It can't infer the correct values itself.
I mean "require that the caller runs __init__ with all the construct-only properties by not having a default value"; as you note below, this means breaking API whenever new construct-only properties are defined.
> And making the caller
> explicitly specify values for all construct-only properties would be annoying.
> And would also mean that adding a new construct-only property would become an
> API break.
> (And FTR, note that there are also construct-only GObject properties that
> *aren't* mandatory to specify. Eg, GTlsCertificate:issuer.)
yes; those are the two main reasons why construct-only properties are evil.
so, at this point the options are:
- add another G_PARAM_CONSTRUCT_REQUIRED flag, and expand (or, probably, shrink) the GParamFlags enumeration;
- add a new annotation to the property gtk-doc annotation, something like:
* GBinding:source: (required):
* Since: Blah
which gets saved into the introspection data as another flag.
*** This bug has been marked as a duplicate of bug 649662 ***