GNOME Bugzilla – Bug 561264
How to tell static methods and constructors apart
Last modified: 2015-02-07 16:54:31 UTC
From IRC (2008-11-16):
04:46 < owen> walters: do you know if there is any constraint on number/signature of constructors, or is the idea that "some magic happens" in the language binding and some get turned into constructors, and others into static methods?
04:47 < walters> there is no constraint in introspection right now
04:47 < walters> oh, you mean how to distinguish between a static method and a constructor if they both return Foo*?
04:47 < walters> right now the heuristic is "presence of _new"
04:48 < owen> walters: e.g., is it OK to have new_from_file(const char *filename) and new_from_stock(const char *stock_id) both tagged as constructor?
04:48 < walters> JGIR goes to some length to deal with that one
04:48 < walters> i don't know whether we should allow it or not
04:49 < walters> maybe introspection should say "ok, these are static methods"
04:49 < walters> btw i am working on the static method stuff right now
04:50 < owen> having is_constructor mean "new appears somewhere in the name" doesn't seem to be that useful
04:51 < walters> yeah, true
04:52 < owen> "static method that returns a newly allocated object of the class type" is otherwise represented in the typelib
04:52 < walters> oh one detail is GtkWidget *my_object_new();
04:53 < walters> right now if we see _new we change the return type to the matching type
04:53 < owen> "is usefully overloaded into a constructor" is something that really needs to come from annotations
04:54 < walters> i'm not opposed to that
04:54 < owen> since otherwise, when new_from_stock() is added, the scanner might change
04:54 < owen> Though I think the scanner could usefully set that flag automatically for anything that is named _simply_ "new()"
04:56 < owen> Basically "is usefully overloaded into a constructor" would be a promise that no other method with the same (or very similar) signature would be added also with that flag
04:56 < owen> For GtkWidget *my_object_new(); ... note what is happening there is that the scanner sees the wrong type information ... since the result actualy has a static type of MyObject
04:59 < walters> how so?
05:01 < walters> what do you mean by static type?
05:09 < owen> THe introspection information really should have the function as if it was "MyObject *my_object_new()"
05:09 < owen> Writing GtkWidget * is just a C convenience ... we know (statically - ahead of time) that isinstance(result, MyObject)
05:10 < walters> oh, yes that's what I'm saying it does
05:10 < walters> *if* we see _new
05:10 < walters> this stuff is in glibtransformer.py:_parse_method_common
05:11 < owen> Oh, I thought you were saying that it was setting the is_constructor flag if it saw _new
05:11 < walters> i think you're probably right we want a constructor annotation
> 05:09 < owen> THe introspection information really should have the
> function as if it was "MyObject *my_object_new()"
> 05:09 < owen> Writing GtkWidget * is just a C convenience ... we know
> (statically - ahead of time) that isinstance(result, MyObject)
related to this, I have two methods in libsoup that take the wrong first argument type, for convenience:
void soup_auth_domain_basic_set_auth_callback (SoupAuthDomain *domain,
it really ought to be a "SoupAuthDomainBasic *", but...
Anyway, there doesn't seem to be a way to annotate my way out of this currently. So a generic (actual-type TYPE) annotation might be good.
Another case that might make use of this is when you kludge a method's prototype to match a typedef:
guint soup_str_case_hash (gconstpointer key);
gboolean soup_str_case_equal (gconstpointer v1,
The gconstpointers here are all "really" const char *.
If I've understood it correctly, what tagging some static methods as constructors is trying to achieve is that given, for example, these "C constructors":
GtkWidget *gtk_button_new_with_label(const char *label);
GtkWidget *gtk_button_new_with_mnemonic(const char *mnemonic);
using 'is-constructor' flag on with_label() would mean that
1) the return value is really a) (transfer full) b) GtkButton and
2) if the language supports it, a 'GtkButton("foo")' constructor call should call with_label() rather than with_mnemonic()
3) no other method with similar signature can have 'is-constructor' flag
Now, 1a) is already default behavior for objects and has working annotation and 1b) is implicitly determined from the presence of '_new' in the function name, and should probably be supported through annotations as well (comment 1 and bug 561253)
2) feels like a potentially useful way to map constructor calls to function calls based on signature
3) what does "similar" mean, and who checks/enforces it? I'd guess the most universal rule would be to require constructors have different number of arguments to avoid possibilities for ambiguities due to different implicit type conversions in different languages.
There is a related problem to this. It doesn't only affect static methods, but also constructors which take an object of the same class as first argument. I just stumbled over this while working on bug 635253. Gtk has a radio button constructor:
* @radio_group_member: (allow-none): widget to get radio group from or %NULL
* @label: a text string to display next to the radio button.
* Creates a new #GtkRadioButton with a text label, adding it to
* the same group as @radio_group_member.
* Returns: (transfer none): a new radio button.
gtk_radio_button_new_with_label_from_widget (GtkRadioButton *radio_group_member,
const gchar *label)
But g-i doesn't consider that a constructor even though it has "_new_" in it, presumably because it also looks at the type of the first argument and misinterprets that as "self", and thus considers this a method?
This gets turned into
<doc xml:whitespace="preserve">Creates a new #GtkRadioButton with a text label, adding it to
the same group as @radio_group_member.</doc>
<doc xml:whitespace="preserve">a new radio button.</doc>
<type name="Widget" c:type="GtkWidget*"/>
<parameter name="label" transfer-ownership="none">
<doc xml:whitespace="preserve">a text string to display next to the radio button.</doc>
<type name="utf8" c:type="gchar*"/>
which both drops the constructor behaviour, and also silently drops the "allow-none", since the first parameter disappeared entirely.
So I agree that there should be a way to force a method to be a constructor for corner cases like this.
Do we know how common is the problem that Martin mentions?
If it's very uncommon and just happens with convenience constructors, we could mark those as introspectable=0 and let bindings authors add overrides if they really think it brings good valued to application authors.
This may be more widespread than I thought, we also have this problem in
GdkWindow* gdk_window_new (GdkWindow *parent, GdkWindowAttr *attributes, gint attributes_mask)
This should be either a constructor or a (factory) static method, but not a method.
Created attachment 178631 [details] [review]
Allow constructors with instances of the same class as their first argument
So we can use constructors such as gtk_radio_button_new_with_label_from_widget
(In reply to comment #6)
> Created an attachment (id=178631) [details] [review]
> Allow constructors with instances of the same class as their first argument
> So we can use constructors such as gtk_radio_button_new_with_label_from_widget
> and gdk_window_new.
Tests in g-i pass without modification and by diffing the gtk and gdk .gir we can see that this causes only the intended changes.
Review of attachment 178631 [details] [review]:
There was *definitely* a reason this code was added; if I use "git annotate", I get:
Author: Colin Walters <email@example.com>
Date: Wed Sep 8 12:18:51 2010 -0400
scanner: Don't mark as constructors things that are more obviously methods
If the first parameter matches the origin, don't scan as a constructor.
Happened in practice with meta_screen_append_new_workspace from mutter.
So, here we have a method that just happens to have "_new" in the name. I don't see a way to have both:
* The heuristic on _new
* Somehow picking between method and constructor automatically
We've obviously needed annotations for a long time here...but I'm not sure which way to lean. I think I'd say we should require annotations on constructors that take an instance as the first argument.
Created attachment 178952 [details] [review]
Add (constructor) annotation
One more possibility to deal with this issue
Review of attachment 178952 [details] [review]:
@@ +576,3 @@
node.foreign = True
+ if OPT_CONSTRUCTOR in block.options and hasattr(node, 'is_constructor'):
isinstance(node, Function) instead of hasattr() please.
@@ +964,2 @@
def _pair_constructor(self, func, subsymbol):
+ if not func.is_constructor and \
This is similar to the one I commented on in the (function) annotation in that it seems weird to me to mix the case where the user explicitly told us something is a constructor via annotation with the case where we're trying to infer it.
If you could do the same refactoring here I think the code would come out significantly cleaner.
Or at least, it really deserves a comment. Right now the code will be too mysterious for someone reading it later.
Created attachment 179507 [details] [review]
Add (constructor) annotation
Review comments addressed.
Review of attachment 179507 [details] [review]:
Looks good, thanks.
Attachment 179507 [details] pushed as 2c36790 - Add (constructor) annotation
[Mass-moving gobject-introspection tickets to its own Bugzilla product - see bug 708029. Mass-filter your bugmail for this message: introspection20150207 ]