After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 561264 - How to tell static methods and constructors apart
How to tell static methods and constructors apart
Status: RESOLVED FIXED
Product: gobject-introspection
Classification: Platform
Component: general
2.19.x
Other Linux
: Normal enhancement
: ---
Assigned To: gobject-introspection Maintainer(s)
gobject-introspection Maintainer(s)
Depends on:
Blocks:
 
 
Reported: 2008-11-17 19:04 UTC by Andreas Rottmann
Modified: 2015-02-07 16:54 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
Allow constructors with instances of the same class as their first argument (1.87 KB, patch)
2011-01-18 15:47 UTC, Tomeu Vizoso
reviewed Details | Review
Add (constructor) annotation (6.14 KB, patch)
2011-01-21 16:33 UTC, Tomeu Vizoso
reviewed Details | Review
Add (constructor) annotation (7.11 KB, patch)
2011-01-28 12:31 UTC, Tomeu Vizoso
committed Details | Review

Description Andreas Rottmann 2008-11-17 19:04:54 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
Comment 1 Dan Winship 2008-11-17 20:00:08 UTC
> 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,
				  gconstpointer v2);

The gconstpointers here are all "really" const char *.
Comment 2 Tommi Komulainen 2008-11-18 00:45:28 UTC
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.
Comment 3 Martin Pitt 2010-11-19 15:36:47 UTC
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:

/**
 * gtk_radio_button_new_with_label_from_widget:
 * @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.
 */
GtkWidget*
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
      <method name="new_with_label_from_widget"
              c:identifier="gtk_radio_button_new_with_label_from_widget">
        <doc xml:whitespace="preserve">Creates a new #GtkRadioButton with a text label, adding it to
the same group as @radio_group_member.</doc>
        <return-value transfer-ownership="none">
          <doc xml:whitespace="preserve">a new radio button.</doc>
          <type name="Widget" c:type="GtkWidget*"/>
        </return-value>
        <parameters>
          <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*"/>
          </parameter>
        </parameters>
      </method>

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.

Thanks!
Comment 4 Tomeu Vizoso 2011-01-17 12:55:07 UTC
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.
Comment 5 Tomeu Vizoso 2011-01-18 15:05:20 UTC
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.
Comment 6 Tomeu Vizoso 2011-01-18 15:47:29 UTC
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
and gdk_window_new.
Comment 7 Tomeu Vizoso 2011-01-18 15:48:36 UTC
(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.
Comment 8 Colin Walters 2011-01-18 16:26:43 UTC
Review of attachment 178631 [details] [review]:

There was *definitely* a reason this code was added; if I use "git annotate", I get:

commit 5140ec172415192af4f406b1fd5ff4615caf1386
Author: Colin Walters <walters@verbum.org>
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.
Comment 9 Tomeu Vizoso 2011-01-21 16:33:46 UTC
Created attachment 178952 [details] [review]
Add (constructor) annotation

One more possibility to deal with this issue
Comment 10 Colin Walters 2011-01-21 20:07:05 UTC
Review of attachment 178952 [details] [review]:

::: giscanner/maintransformer.py
@@ +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.
Comment 11 Tomeu Vizoso 2011-01-28 12:31:30 UTC
Created attachment 179507 [details] [review]
Add (constructor) annotation

Review comments addressed.
Comment 12 Colin Walters 2011-01-28 15:51:12 UTC
Review of attachment 179507 [details] [review]:

Looks good, thanks.
Comment 13 Tomeu Vizoso 2011-01-28 15:58:14 UTC
Thanks!

Attachment 179507 [details] pushed as 2c36790 - Add (constructor) annotation
Comment 14 André Klapper 2015-02-07 16:54:31 UTC
[Mass-moving gobject-introspection tickets to its own Bugzilla product - see bug 708029. Mass-filter your bugmail for this message: introspection20150207 ]