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 320482 - provide G_DEFINE_TYPE like macros for interfaces
provide G_DEFINE_TYPE like macros for interfaces
Status: RESOLVED FIXED
Product: glib
Classification: Platform
Component: gobject
2.22.x
Other Linux
: Normal enhancement
: ---
Assigned To: Tim Janik
gtkdev
: 444060 (view as bug list)
Depends on:
Blocks:
 
 
Reported: 2005-11-02 10:05 UTC by Sven Herzberg
Modified: 2011-02-18 16:14 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
patch that defines G_DEFINE_INTERFACE as described above (2.18 KB, patch)
2007-03-16 16:12 UTC, Dan Winship
reviewed Details | Review
updated patch (7.50 KB, patch)
2008-01-09 17:20 UTC, Dan Winship
none Details | Review
updated G_DEFINE_INTERFACE patch (7.09 KB, patch)
2008-09-08 19:43 UTC, Dan Winship
none Details | Review
patch to make gio use G_DEFINE_INTERFACE (22.05 KB, patch)
2008-09-08 19:47 UTC, Dan Winship
none Details | Review

Description Sven Herzberg 2005-11-02 10:05:46 UTC
It would be great to have some macros that would make writing interfaces as easy
as G_DEFINE_TYPE does for classes.

You can take my code from
http://cvs.gnome.org/viewcvs/criawips/copy-src/helpers/gobject-helpers.h
Comment 1 Matthias Clasen 2005-11-04 19:35:34 UTC
You will have to convince rambokid that this is a good idea.
Comment 2 Matthias Clasen 2005-11-04 19:36:14 UTC
You will have to convince rambokid that this is a good idea.
Comment 3 Tim Janik 2006-05-31 10:40:58 UTC
Sven, can you supply a patch implementing the suggested macros?
Comment 4 Tim Janik 2007-03-12 11:47:09 UTC
flagging NEEDINFO until there's any further progress.
Comment 5 Dan Winship 2007-03-16 16:11:54 UTC
OK, comparing criawips's G_DEFINE_IFACE
(http://svn.gnome.org/viewcvs/criawips/trunk/copy-src/helpers/gobject-helpers.h?revision=712&view=markup)
and libsoup's SOUP_MAKE_INTERFACE
(http://svn.gnome.org/viewcvs/libsoup/trunk/libsoup/soup-types.h?revision=795&view=markup)
there are a few minor differences and one major one.

The major difference is that criawips sets the GTypeInfo's
"class_init", but libsoup sets its "base_init". Gtk is inconsistent
internally: GtkCellEditable, GtkEditable, GtkFileFolder,
GtkFileSystem, GtkPrintOperationPreview, GtkTreeModel, and
GtkTreeSortable use base_init. GtkFileChooser, GtkFileChooserEmbed,
and GtkRecentChooser use class_init.

The GObject docs say that interfaces should use base_init... AFAICT,
the only time there's a big difference is when you have a class that
implements an interface, and then you subclass the class and
reimplement the interface in the subclass. If the interface
initializes its vtable in base_init, then the subclass will default to
the method implementations defined by the interface. But if the
interface initializes its vtable in class_init, then the subclass will
default to the method implementations defined by its superclass.

If you don't have a subclass reimplementing one of its parent class's
interfaces, I can't see any difference between the two, besides the
fact that base_init needs an "if (!initialized) ..." check around
signal and property definitions to make sure they only run once. And
we couldn't put that check into the G_DEFINE_INTERFACE wrapper,
because if we did it would just make base_init end up working exactly
the same as class_init anyway.

So the choices seem to be:

	1. Have G_DEFINE_INTERFACE set class_init
	2. Have G_DEFINE_INTERFACE set base_init (and force the caller
	   to do an "if (!initialized)" check if necessary)
	3. Have G_DEFINE_INTERFACE set both of them, and force the
	   caller to define both init methods (one for vtable, one for
	   signals/properties).

I think #1 makes the most sense (for a general-use G_DEFINE_INTERFACE
macro). If the caller needs to do something more obscure, they can
write out the get_type method by hand.


The minor differences:

criawips expects a class structure called "FooIface", libsoup expects
one called "FooClass". Gtk uses "Iface" everywhere except
"GtkEditableClass", so I guess "Iface" is the preferred convention.
(Should we rename the foo_class_init method to foo_iface_init to
match?)

criawips requires the caller to pass in the interface's parent type.
G_TYPE_INTERFACE isn't DEEP_DERIVABLE, so we can pretty safely assume
the parent type is G_TYPE_INTERFACE.

criawips calls "g_type_interface_add_prerequisite(type, G_TYPE_OBJECT);".
(libsoup doesn't provide any way to set a prereq.) Gtk uses various different
prerequisite types on different interfaces, so that should probably be made a
parameter of the macro.
Comment 6 Dan Winship 2007-03-16 16:12:40 UTC
Created attachment 84726 [details] [review]
patch that defines G_DEFINE_INTERFACE as described above
Comment 7 Dan Winship 2007-06-04 19:21:24 UTC
*** Bug 444060 has been marked as a duplicate of this bug. ***
Comment 8 Matthias Clasen 2007-11-23 06:40:47 UTC
Patch looks good to me. Tim ?
Comment 9 Dan Winship 2008-01-09 17:20:07 UTC
Created attachment 102479 [details] [review]
updated patch

Updates the previous patch to use g_once_init_enter/g_once_init_leave like G_DEFINE_TYPE does now, and includes documentation. (Also updates the G_DEFINE_TYPE_WITH_CODE docs to reflect the current expansion of that macro.)
Comment 10 Tim Janik 2008-02-05 18:43:10 UTC
(In reply to comment #9)
> Created an attachment (id=102479) [edit]
> updated patch
> 
> Updates the previous patch to use g_once_init_enter/g_once_init_leave like
> G_DEFINE_TYPE does now, and includes documentation. (Also updates the
> G_DEFINE_TYPE_WITH_CODE docs to reflect the current expansion of that macro.)

thanks Dan, i have a few smaller issues with the patch:
1) the initializer name should be _default_init if that's the function pointer it implements.
2) "Iface" is a very wierd abbreviation, it might be ok for non-API words like variables, but for programming interfaces we should use proper nameing like "Interface¨.
3) i think we should check for TYPE_PREREQ!=0 in case the user doesn't want to use it and passes in 0.

an adapted version of your macro is in glib/gobject/tests/threadtests.c, i'd apprechiate you reviewing it. i think we can add this to gtype.h as is, unless more issues are being brought up (and when doing that, you'll be properly credited, which i forget for threadtests.c, sorry ;)
Comment 11 Dan Winship 2008-02-05 21:08:36 UTC
(In reply to comment #10)
> 1) the initializer name should be _default_init if that's the function pointer
> it implements.

Ok... but it's not called _default_init. It's setting the class_init pointer.

Although "_interface_init" instead of "_class_init" would make sense, and would make the initializer name match the class struct name.

> 2) "Iface" is a very wierd abbreviation

Agreed. "Interface" is better. (I was just copying existing convention.)

> 3) i think we should check for TYPE_PREREQ!=0 in case the user doesn't want to
> use it and passes in 0.

I thought about that before and figured the user could just pass G_TYPE_OBJECT in that case. But this is probably nicer.
Comment 12 Tim Janik 2008-02-05 21:19:02 UTC
(In reply to comment #11)
> (In reply to comment #10)
> > 1) the initializer name should be _default_init if that's the function pointer
> > it implements.
> 
> Ok... but it's not called _default_init. It's setting the class_init pointer.

right, but there is no "class" for interfaces, other than the default interface vtable that gets copied over when an interface is setup for a particular object class via GInterfaceInitFunc. so the only reason for someone to supply a function pointer in the GTypeInfo.class_init slot for interfaces would be to provide an initializer for the default interface structure (e.g. to default-initialize interface functions). i hope this makes my point clearer... ;)

> > 3) i think we should check for TYPE_PREREQ!=0 in case the user doesn't want to
> > use it and passes in 0.
> 
> I thought about that before and figured the user could just pass G_TYPE_OBJECT
> in that case. But this is probably nicer.

well, interfaces are not neccessarily bound to be implemented only for G_TYPE_OBJECT derived types (allthough that's probably the only _practical_ use currently).
Comment 13 Dan Winship 2008-09-08 19:43:55 UTC
Created attachment 118322 [details] [review]
updated G_DEFINE_INTERFACE patch

Incorporates the previous suggestions: Iface->Interface, class_init->default_init, allow 0 for TYPE_PREREQ. Also moves the docs inline.
Comment 14 Dan Winship 2008-09-08 19:47:42 UTC
Created attachment 118323 [details] [review]
patch to make gio use G_DEFINE_INTERFACE

Trying to port gio to use G_DEFINE_INTERFACE turns up some problems:

    - since they use "FooIface" in their public API, but the macro only
      handles "FooInterface", we have to add a typedef. (A #define wouldn't
      work, unless we wanted to "#define Interface Iface".) Maybe if we
      really like Interface and hate Iface we'd want to move the typedefs
      to the .h files and deprecate the Iface names.

    - Several gio interfaces define signals rather than just filling in the
      vtable, making the name "default_init" less accurate.

but it works
Comment 15 Dan Winship 2009-04-24 14:18:53 UTC
ping?
Comment 16 Alexander Larsson 2009-12-01 09:48:25 UTC
I tried to ping tim for a comment but he hasn't commented here, but as per comment #10 timj seems ok with commiting this. I think it looks good too, so I commited this.

I agree that default_init is not super-accurate since we also sometimes set up signals there, but this is not so critical imho, its more important to get this in so people can start using it.
Comment 17 Steve Frécinaux 2010-01-15 10:33:00 UTC
(In reply to comment #10)
> 2) "Iface" is a very wierd abbreviation, it might be ok for non-API words like
> variables, but for programming interfaces we should use proper nameing like
> "Interface¨.

It might be a bit late, but as discussed on IRC with alex lately, I don't really agree on this, mostly for the sake of consistency:

1/ The current usage is to use the (maybe weird but so common) Iface suffix for interface types, at least in Gtk+ and glib, and probably in a lot of other related libraries.

2/ Along with those name types come the usual "accessor" macro (for instance G_FILE_GET_IFACE) and the eventual _IFACE cast macro. For the sake of consistency, those should probably be renamed as well, if the -iface suffix is evil.

3/ "Interface" is even longer than "Iface", which, combined with the _GET_IFACE stuff, will make the function/macro calls and iface-related code even more verbose.

4/ As stated in comment 14, using the new macro with the Interface suffix forces one to define a whole lot of new typedefs, while not being able to drop the old ones, for API compat. It's quite opposite to reducing the code base. Also some tools might be bound to the Iface names.

So for the sake of consistency and convenience, I'd rather go with Iface as a suffix than Interface.


Also, not related but still, comment 14 seems to suggest that class_init would indeed be more adapted than base_init, but to me it is useful to have a reimlementation of an interface by a child class to default to the already-implemented function, and to allow chaining to the parent's implementation of said iface function (this is to avoid having to write all the static functions just to chain up if you're overriding a method from an interface one of your parents already implemented).
Comment 18 Steve Frécinaux 2010-01-15 10:40:04 UTC
A practical example for the chainup thing:

I have a PeasConfigurableIface which provides two methods: is_configurable and get_configure_dialog.

I have a PeasPlugin which implements it this way: is_configurable returns true if get_configure_dialog is not null.

Now I have python bindings which define a PeasPythonPlugin Gobject (in C) and "overrides" is_configurable to return true if there is a python method called "create_configure_dialog" in the python object, because the C object's method has been changed to the python wrapper.

What I'd like here is to make it possible for a PeasPythonPlugin subclass to re-implement PeasConfigurableIface and to see its create_configure_dialog overriden while keeping the existing behaviour on the is_configurable method. This is all for convenience, of course.
Comment 19 Dan Winship 2010-01-15 12:35:09 UTC
(In reply to comment #17)
> It might be a bit late

well, it's already been committed using "Interface", but it's not stable yet, so...

> Also, not related but still, comment 14 seems to suggest that class_init would
> indeed be more adapted than base_init, but to me it is useful to have a
> reimlementation of an interface by a child class to default to the
> already-implemented function, and to allow chaining to the parent's
> implementation of said iface function

That is what using class_init does, and that's what we do, though the method
is called foo_default_init, not foo_class_init, for reasons I don't understand.