mom.texi 4.1 KB
@c This is part of the GNU Mailutils manual.
@c Copyright (C) 1999,2000,2001,2002 Free Software Foundation, Inc.
@c See file mailutils.texi for copying conditions.
@comment *******************************************************************

@subsection Mailutils Object Model
Mailutils is written in C, the language is widely supported on
many platforms and the ABI (Binary Interface) for linking objects
with other languages (like Guile, Java, ...) is well-defined.

The C language does not provide support for object oriented programming,
but by using structures and pointers to function, it is possible to provide
a simple framework.

Every Mailutils object has a corresponding C structure holding its interface
and specific data.  For example mu_object_t, is the root object and all mailutils objects
extends it:

@example
struct _mu_object;
typedef struct _mu_object* mu_object_t;

/* Defintion of the interface for mu_object */
struct _mu_object_vtable
@{
  int  (*create)   (mu_object_t *object);
  void (*destroy)  (mu_object_t *object);
  void (*notify)   (mu_object_t object, int event, void *data);
@}

struct _mu_object
@{
  struct _mu_object_vtable *vtable;
  int type;
@}
@end example

The @var{vtable} is an array of pointers to function, it provides the interface
or the list of function for this object.  The library provides wrapper to
access the functions instead using the @var{vtable} directly.

@example
int mu_object_notify(mu_object object, int event, void *data)
@{
  if (object == NULL || object->vtable == NULL
      || object->vtable->notify == NULL)
    return MU_ERR_NOT_SUPPORTED;
  return object->vtable->notify (object, event, data);
@}
@end example

Instead of using macros or the vtable directly.
@example
#define mu_object_notify(o, evt, d)  ((o)->vtable->notify(o, evt, d))
@end example

@subsubsection Implementing an interface

@comment ***********************************************************
@comment This is not a very good/usefull example, we should do one using
@comment header or message, something usefull that would clarify the concepts
@comment better and at the same could be reuse in code by clients.
@comment
@comment For example mime_t "extends" message_t, this is a good example
@comment since you can consider a mime_t as a message_t but with extra functions.
@comment ***********************************************************

For a more concrete implementation, lets say we are implementing some caching mailbox
but we need to keep a better track of the objects in our implementation.
We take the approach of simple reference counting and extend the mu_object_t.

@example
#include <mailutils/sys/object.h>

struct my_object;
typedef struct refcount* refcount;

struct refcount_vtable
@{
   struct _mu_object_vtable base;  
   int (*increment)(refcount_t);
   int (*decrement)(refcount_t);
@} 

struct refcount
@{
  struct refcount_vtable * vtable;
  int count;
@}

static int
refcount_increment (mu_object_t obj)
@{
   refcount_t refcount = (refcount_t)obj;
   refcount->count++;
   return refcount->count;
@}

static int
refcount_decrement (mu_object_t obj)
@{
   refcount_t refcount = (refcount_t)obj;
   if (refcount->count > 0)
     refcount->count--;
   return refcount->count;
@}

int
my_mu_object_create (mu_object_t *pobject)
@{
   static struct refcount_vtable* vtable;
   refcount_t ref;

   if (object == NULL)
     return EINVAL;

   if (!vtable)
    @{
      vtable = calloc(1, sizeof(*vtable));
      if (vtable == NULL)
        return ENOMEM;
      vtable->base.vtable = &_mu_object_vtable; // FIXME where can they get the base vtable
      vtable->increment = refcount_increment;
      vtable->decrement = refcount_decrement;
    @}

   ref = malloc(sizeof *ref);
   ref->base = vtable;
   *pobject = &ref->base.vtable
   return 0;
@}
@end example

The interface adds a @code{decrement} and @code{increment} to the @code{mu_object_t}
interface. Creating a @code{refcount_t} can be savely typecast to @code{mu_object_t},
for example:

@example
refcount_t ref;
mu_object_t obj;
refcount_create (&ref);

/* send a notification to the listeners of an event.  */
mu_object_notify ((mu_object_t)ref, 5, NULL)

@end example