#107397 (Re: type_info macro generation ...)
- From: Tim Janik <timj gtk org>
- To: Owen Taylor <otaylor redhat com>
- Cc: Michael Meeks <michael ximian com>, Gtk Hackers <gtk-devel-list gnome org>
- Subject: #107397 (Re: type_info macro generation ...)
- Date: Fri, 9 Jan 2004 15:41:08 +0100 (CET)
On Fri, 19 Sep 2003, Owen Taylor wrote:
> On Fri, 2003-09-19 at 09:14, Michael Meeks wrote:
> > Hi Owen,
> >
> > Just poking at the GTypeInfo stuff, and I appreciate how controversial
> > eg. bonobo's "DO_TYPE_EVERYTHING" type macros are (pwrt. interfaces etc.
> > etc.).
> >
> > It struck me that if instead of having to do:
> >
> > static const GTypeInfo foo_info = {
> > sizeof(FooClass), NULL, NULL, foo_class_init, NULL, NULL,
> > sizeof(Foo), 0, foo_init, NULL
> > };
> >
> > or somesuch; perhaps a significant size saving could be had from a
> > macro something like:
> >
> > G_TYPEINFO_DECL(foo, Foo);
> >
> > or somesuch ? - that could shrink the get_type by a good number of
> > lines for the very common case.
>
> As far as I know, there's nothing at all controversial about the libgsf
> style of macro that defines the entire get_type() function. That is,
> everybody who has commented on it thinks it's a good idea. Still haven't
> heard from Tim.
>
> The BONOBO_BOILERPLATE style with the prototypes for class_init and init
> and the class_init trampoline to set the parent type, I think *is*
> to comprehensive. Plus, it doesn't do interfaces.
>
> But I like the libgsf style a lot.
after looking at the various boilerplate macros in CVS, the different
(sometimes project-specific) features they offer and the things that
can be (were) gotten wrong, i went for a version that allowes great
flexibility and reduces overhead up to a reasonable extend, while taking
care of as much of the mechanic error-prone tasks as possible and staying
reasonably simple.
for convenience reasons and because i don't expect any actual harm,
i took the freedom to clutter the G_DEFINE and G_IMPLEMENT namespaces
(similar to the pango variants). the result is:
/* --- GType boilerplate --- */
/* convenience macros for type implementations, which for a type GtkGadget will:
* - prototype: static void gtk_gadget_class_init (GtkGadgetClass *klass);
* - prototype: static void gtk_gadget_init (GtkGadget *self);
* - define: static gpointer parent_class = NULL;
* parent_class is initialized prior to calling gtk_gadget_class_init()
* - implement: GType gtk_gadget_get_type (void) { ... }
* - support custom code in gtk_gadget_get_type() after the type is registered.
*
* macro arguments: TypeName, type_name, TYPE_PARENT, CODE
* example: G_DEFINE_TYPE_WITH_CODE (GtkGadget, gtk_gadget, GTK_TYPE_WIDGET,
* g_print ("GtkGadget-id: %lu\n", g_define_type_id));
*/
#define G_DEFINE_TYPE(TN, t_n, T_P) G_DEFINE_TYPE_INTERNAL (...)
#define G_DEFINE_TYPE_WITH_CODE(TN, t_n, T_P, _C_) G_DEFINE_TYPE_INTERNAL (...)
#define G_DEFINE_ABSTRACT_TYPE(TN, t_n, T_P) G_DEFINE_TYPE_INTERNAL (...)
#define G_DEFINE_ABSTRACT_TYPE_WITH_CODE(TN, t_n, T_P, _C_) G_DEFINE_TYPE_INTERNAL (...)
/* convenience macro to ease interface addition in the CODE
* section of G_DEFINE_TYPE_WITH_CODE() (this macro relies on
* the g_define_type_id present within G_DEFINE_TYPE_WITH_CODE()).
* usage example:
* G_DEFINE_TYPE_WITH_CODE (GtkTreeStore, gtk_tree_store, G_TYPE_OBJECT,
* G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL,
* gtk_tree_store_tree_model_init));
*/
#define G_IMPLEMENT_INTERFACE(TYPE_IFACE, iface_init) { \
static const GInterfaceInfo g_implement_interface_info = { \
(GInterfaceInitFunc) iface_init, \
}; \
g_type_add_interface_static (g_define_type_id, TYPE_IFACE, &g_implement_interface_info); \
}
on the pro side, a brief test object implementation is less than 20 lines:
/* --- GxkGadget --- */
typedef struct {
GtkWidget parent_instance;
} GtkGadget;
typedef GtkWidgetClass GtkGadgetClass;
GType gtk_gadget_get_type (void);
G_DEFINE_TYPE (GtkGadget, gtk_gadget, GTK_TYPE_WIDGET);
static void
gtk_gadget_class_init (GtkGadgetClass *klass)
{
}
static void
gtk_gadget_init (GtkGadget *self)
{
}
/* --- done! --- */
and a more sophisticated version could use:
static void gtk_gadget_tree_model_init (GtkTreeModelIface *iface);
static void gtk_gadget_tree_sortable_init (GtkTreeSortableIface *iface);
G_DEFINE_TYPE_WITH_CODE (GtkGadget, gtk_gadget, GTK_TYPE_WIDGET,
G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL,
gtk_gadget_tree_model_init);
G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_SORTABLE,
gtk_gadget_tree_sortable_init);
);
on the con side, though the majority of the common cases is covered,
not all possible type registration cases are supported:
1) type implementations are forced to provide class_init()
as the class init function is prototyped within G_DEFINE_TYPE()
2) type implementations are forced to provide instance_init()
as the instance init function is prototyped within G_DEFINE_TYPE()
i collected some data [1] from CVS to figure whether this would impose a
noticable inconvenience. it turns out that in CVS HEAD we have about 1700
uses of GTypeInfo, out of which:
90.18% provide class_init and instance_init
6.16% provide only class_init
3.64% provide neither
so with G_DEFINE_TYPE() enforcing the implementation of instance_init()
and class_init(), the effective penalty out of a 100 cases is:
3.64% forces extra class_init() implementation
9.80% forces extra instance_init() implementation
in other words, that is one empty instance_init() prototype per saving
10 get_type()-implementations. i think that's an accaptable trade off
for avoiding class_init_function_name and instance_init_function_name
arguments for G_DEFINE_TYPE() and being able to provide the prototypes
automatically.
3) instance_init(Instance *self, InstanceClass *real_class) implementations
that need the real instance class as argument upon initialization of super
types are not possible with G_DEFINE_TYPE() since it prototypes the
instance_init() function without the extra class argument. from my
experience, code using this feature is rare enough though to justify
implementing get_type() from scratch.
4) code using the same class_init() function to implement multiple types
by parameterizing them via class_data are not possible with G_DEFINE_TYPE()
either, due to prototyping class_init() without the extra class_data()
argument, and due to not allowing class_data modification within the
_get_type() implementation. again, this facility seems to be exploited
rarely enough to justify get_type() implementations from scratch.
5) code not needing parent_class will get it anyway. that should be negligible
as many objects want a parent_class pointer and the overhead of providing
it unnecessarily is an extra pointer and one extra function call per class.
6) G_DEFINE_TYPE() can't be used multiple times in a single C file, due
to the multiple parent_class pointers clashing. if people really are
defining lots of small objects in a single C file, they can cook their
own macro like this:
#define MY_DEFINE_TYPE(TypeName, type_name, TYPE_PARENT) \
G_DEFINE_TYPE_INTERNAL (TypeName, type_name, \
TYPE_PARENT, 0, type_name##_parent_class, {})
and then write code like:
MY_DEFINE_TYPE (GtkGadget, gtk_gadget, GTK_TYPE_WIDGET);
[...]
GTK_WIDGET_CLASS (gtk_gadget_parent_class)->expose_event (...);
final remarks:
i've tested the code with a rough 20 objects, but i'd apprechiate
it if people could give the macros a try, especially the interface and
abstract type variants.
some of the boilerplate definition sets in the various modules also included
macros to call parent class vfunctions, setup empty signal handlers, and a
few other exotic things. i found none of them to be generally usefull
and profitable enough to go into gobject straight. if there's someone
of a different opinion, please start a seperate thread about such macros
on this list.
>
> Regards,
> Owen
>
[1] for those wanting to draw their own figures, drop me a line and i'll
send you the perl script to extract GTypeInfo initialization from the
2+GB of CVS HEAD modules, or the results file right away (ca. 90Kb).
---
ciaoTJ
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]