Re: rework of the Gtk2-Perl type system



muppet <scott asofyet org> writes:

I've run across some problems with the way the Gtk2 bindings handle gtk
types.  I have an idea for how to rework the mechanism, but i'd like to
bounce my thoughts off of you guys and see if i've missed anything.

This will be a little lengthy, but i really want your input -- please
respond!

Thanks for your thinking. You're absolutely right to discuss
existing mechanisms. The soone we ameliorate them, the better. No
one writes perfect code, anyway.


[...]

I'd like to change the way the perl bindings handle GType class to perl
package mappings such that the system is more flexible and extensible. 
This will not benefit only me -- it will help any project that needs to
create bindings for a GObject-based library.

This is a very valid motivation, with which I entirely agree.


[...]

So far so good.  these are implemented using some utility methods:

   get_class
      given a GObject pointer, return the perl package in which
      this particular GObject's GType belongs (e.g., for a GtkWidget
      pointer, returns "Gtk2::Widget")

   get_class_from_classname
      given the name of a GType (e.g., "GtkWidget"), return the
      corresponding perl package (e.g., "Gtk2::Widget").

Firstly, these need to be renamed to avoid namespace pollution and
runtime symbol clashes,

Of course, you're right. I've always voiced on this ML that we
should prepend our non-static internal functions with gtk2_perl,
I've even modified all my functions in that respect. Not to blame
others, but these functions are not mine :).

You find the real problems when you dig into build_class_name (which is
called by both get_class and get_class_name).  This function attempts to
convert a class name into a package name according to a hard-coded list
of mapping rules.  If the class cannot be mapped according to any of
these rules, the mapping fails, and get_class_from_class_name (which is
called by get_class, too) croaks.

There's also another problem, but I don't think it can be
addressed (or at least I don't know how), due to the way C works:
when you use get_class with a boxed type (or anything else,
actually) instead of a GObject, you segfault trying to
dereference fields of the supposed GObject structure. This is
unsafe. But this is C :/.

This makes it impossible to use with Gtk2-Perl any class which does not
fit those mapping rules, so basically, anything that's not part of Gtk
or Gnome.  (the Gnome mappings are hardcoded into the Gtk bindings, even
though they are distributed separately).

Not to say that the mapping rules are a bit hackish, especially
for GLib stuff.
 

[...]

The fundamental assumption here is that the object has been implemented
with its own *.pm, as is the case with Inline.  I could write a book on
why i think Inline is not appropriate for a project of this size, and in
fact the requirement at every class has a separate pm is one of the
reasons, but i'll reserve that argument for a future treatise.  Suffice
it to say that if we want to encourage people to use the Gtk2 bindings
we shouldn't require that they use Inline.  (i have no intention of
using Inline for my own project, because i find XS to be far more
straightforward when you already have to deal with perl's internal API.)

Basically, if you don't have a *.pm for the class you've mapped, the
script will die in the require_pv call because perl can't find the
required file.

Well, according to perlapi(1), it's not entirely true. The api
call I've chosen seems to be eval'ed (can't remember if I did it
on purpose or not).

       require_pv
               Tells Perl to "require" the file named by the string argument.
               It is analogous to the Perl code "eval "require '$file'"".
               It's even implemented that way; consider using Perl_load_module
               instead.
 

[...]

Both of these could be accomplished by requiring class-to-package
mappings to be registered at runtime.   This registration could happen
in Gtk2->init, or even in a mass bootstrapper.  In Gtk-Perl, for
example, the toplevel bootstrap function calls the boot code for all the
other XS modules; the code for this is generated by paolo's 
ExtUtils::Depends, called from Makefile.PL.  (In fact, ExtUtils::Depends
also installs typemaps and headers and config information needed for
building client modules.  It's very cool, and i think we should use it.)

I confess I'll have to read more of gtk-perl sourcecode: I have
no idea what you're talking about :/.
 
I propose something like

   void gtk2_perl_register_class_mapping (const char * class,
                                          const char * package,
                                          gboolean require);

[...]

On the other hand, it might also be possible to do something like

   void gtk2_perl_register_class_mapping_rule (char * perl_code_to_eval)

which would allow you somehow to specify a substitution pattern for a
whole set of mappings, to be run as a code reference, and successful
results cached to avoid running it again.  I am willing to implement
this, but i want help designing that portion of the interface.

I tend to prefer the first form: it seems more readable and less
error-prone to me. Additionally, because we're talking about more
that one registration, the perl code should also care to return
undef (for example) when the classname given as input is not in
his field of action, because each perl code for each registration
would be called in a row (if I see clearly how this will work).
Means that adding external elements might break existing ones if
the perl code fails to do so... It seems to me that first way of
registration, with an enumeration of all mappings, would be safe
to my eyes.
 

[...]

  char * gtk2_perl_get_package_from_gobject (GObject *)
  char * gtk2_perl_get_package_from_gtype (GType)
  char * gtk2_perl_get_package_from_classname (char *)
     retrieve package names

  GType gtk2_perl_get_type_from_package (char *)
  char * gtk2_perl_get_classname_from_package (char *)
     the other way 'round

Seems good!
 
Also, we could let the GType system do a lot of work for us by
implementing @ISA as a tied variable which uses
gtk2_perl_get_package_from_class, g_type_parent, and
g_type_get_class_from_package.

I don't understand. Maybe if you gave an example, it would help
me to see what you're talking about? Excuse my slow brain..


Thanks for your work. It will help gtk2-perl grow better.


-- 
Guillaume Cottenceau - http://people.mandrakesoft.com/~gc/



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]