26 Sep 2004

I recently hacked up bindings to Gnome for Gnu-smalltalk. I was giving Jeff Waugh some anecdotes about why binding to Gnome VFS was harder than binding to GTK+, and he suggested I blog it…

Theres actually quite a lot of stuff there when I started to think it through, so I’m going to do two (maybe more) entries on it.

Today, I’m going to write about the style of the C headers, and their ability to be trivially machine processed, plus a little more<h3>C header file consistency</h3>

In GTK, there are idioms that made doing bindings from the installed header files very easy.

  • All the structs are defined via
    typedef struct _GnomeFoo GnomeFoo;struct _GnomeFoo{...};

    Which means that a simple Awk script can detect all the object types.

  • The C functions are all laid out consistently:
    returns  gnome_object_name_method_name (parameter...parameter);

In Gnome VFS, neither of these are true, instead we see

  • anonymous structs:
    typedef struct {...} GnomeVFSFoo;

    which prevents trivial analysis.

  • and broken-line function definitions:
    return gnome_vfs_type_method(parameter...parameter);

    which means that trivial pattern matching is not enough to kick into analyse a method mode in awk – you need a full lexer & parser at this point.

The point of this is that, without the use of .defs (which AFAICT are not installed by gnome), gnu smalltalk allows a user to build & improve their language bindings with just the standard development-headers & dynamic libraries installed. The closer the automatic generation makes the bindings, the less override & correction work is needed. The GTK+ headers were fantastic, the Gnome VFS present extra challenges (that I haven’t worked around yet, in point of fact).<h3>Handles and opaque types</h3>

A handle is usually an opaque identifier that one is given by a library, and can pass back to the library upon demand. It might be an index into a table, or a pointer, or even change across minor library upgrades.

IME handles usually have the following properties:

  • Can copy by value
  • the library will provide generic reference and dereference routines for handles
  • Handles are generic across the library
  • Handles are dynamically typed

GnomeVFS has a fairly typical handles concept, FWICT. (I’m not an expert here, as I’ve only looked at the headers, not the full source. Corrections welcomed). There are some unusual aspects….

  • Strange typedefs..
     typedef struct GnomeVFSDirectoryHandle GnomeVFSDirectoryHandle; 

    This is strange because the C function to allocate one then accepts

    GnomeVFSDirectoryHandle **handle

    So, we need to create a pointer to a ponter to a struct whose defintion we never see. Why is this strange? Well, consider:

     typedef struct GnomeVFSDirectory * GnomeVFSDirectoryHandle;.. GnomeVFSDirectoryHandle *handle

    Which will create the same code, but lets us put a handle on the stack without creating our own typedef. We can still hide the definition of GnomeVFSDirectory.

  • There is no library wide Handle reference-dereference methods that I could see. So each handle type is on its own, having potentially difference lifetime semantics. Consistency is good, it allows more predictable behaviour, which encourages programmer productivity (less time finding bugs because handle foo is reference counted, and bar is not.
  • Motivation? GObject is great, it allows dynamic introspection by any language on any object runing with gnome. I can, in smalltalk create an object which knows that it is a Dialog, and pass that to a python-library, which expects anything implementing Widget, interrogates my object and finds it is a Dialog.. which is fantastic. GnomeVFS does not appear to have leveraged this at all. If hiding implementation details was the goal, that is inconsistent (other GnomeVFS structs are defined – but still not using GObject), and if its not to hide implementation details, why not expose the public & private aspects the way that GTK objects do, which seems very well designed (for a C program :)).

In my next blog entry, look for dead chickens, premature optimisation, and awkward calling styles.