[Top][All Lists]

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

Re: guile as extension language

From: Neil Jerram
Subject: Re: guile as extension language
Date: 07 Apr 2002 15:38:14 +0100
User-agent: Gnus/5.0808 (Gnus v5.8.8) Emacs/20.7

>>>>> "Matthew" == Matthew R Wette <address@hidden> writes:

    Matthew> Matthew R Wette writes ...
    >> How is Guile intended to be used as an extension language?
    >> Some extension languages like Perl can be fed commands from the main
    >> application.  I believe the Apache Perl module works this way.
    >> Other extension languages can not be run this way and need to execute
    >> in a separate process, typically communicating via a socket
    >> connection.  I believe the Apache Java servlet modules work this way.
    >> I just read through the Guile 1.5.6 code and it seems that Guile
    >> cannot be fed commands from a parent application like the first case
    >> above.  If you want to use Guile as an *extension* language you need
    >> to run it in a separate process and talk via sockets.  For example, if
    >> I wanted to generate a Guile Apache module it seems I would need to do
    >> it this way.  Is this correct?  

    Matthew> By the way, I noticed that The GIMP uses a separate process
    Matthew> to run script-fu.

    Matthew> My interest here was in exploring the scope of work required to
    Matthew> make a Guile extension for Dia (the gnome graphics app).

Good question!  There's the beginnings of an attempt to explain this
in the reference manual, in the node `Programming Options', but
currently it's pretty sparse, so let's see ...

What are the constituents of the Dia application?

- Most importantly, the `application domain objects' - i.e. shapes,
  templates, connectors, pages, plus the properties of all these

- The code that manages the graphical face of the application,
  including the layout of the objects above.

- The code that handles input events, which indicate that the
  application user is wanting to do something.

(I guess I could've just said `model - view - controller'.)

So, what do you see Guile being able to do for you once you've
incorporated it (in a way yet to be determined)?  I don't know what
you envisage, but my guess is that you're mostly thinking of being
able to manipulate the application domain objects from Scheme.  For

    (for-each-shape current-page
      (lambda (shape)
        (if (square? shape)
            (change-fill-pattern shape diagonal-hatch))))

Assuming that this is the objective, two kinds of thing are needed to
achieve it:

1. You need to write code for "primitives" like `for-each-shape' and
   `shape' such that they access and manipulate your existing data
   structures correctly, and then make these "primitives" available on
   the Scheme level.

2. You need to provide some kind of hook from Dia's main loop that a
   user can use to cause arbitrary Scheme code to be evaluated.

2 is pretty easy, you just have to decide on a mechanism.  Compare
Emacs, for example: when I type `ESC :', I get a prompt where I can
type in any Elisp code, which Emacs will then evaluate.  Or, again
like Emacs, you could provide a mechanism to allow Scheme code to be
bound to a particular key sequence, and evaluate the code when that
key sequence is entered.  Once you have the code that you want to
evaluate, as a null terminated string, you can evaluate it by calling
the `scm_c_eval_string' function.

1 is harder because, for all but the most trivial applications, you
will probably want to allow some representation of your domain objects
to exist on the Scheme level.  This is where the idea of SMOBs comes
in, and with it issues of lifetime management and garbage collection.

To get more concrete about this, consider `shape' in the sample code
above.  For each shape on the current page, the `for-each-shape'
primitive calls `(lambda (shape) ...)' with an argument representing
that shape.  Question is: how is that argument represented on the
Scheme level?  The issues are:

- Whatever the representation, it has to be decodable again by the C
  code for the `square?' and `change-fill-pattern' primitives.

- What happens if the Scheme code stores `shape' in a global variable,
  then that shape is deleted, and later on some other Scheme code
  uses that global variable in a call to, say, `square?' ?

Generally speaking, the answer is something like this:

- Create a structure that wraps the underlying C structure together
  with a status field indicating whether than underlying structure is
  still valid or not:

struct dia_guile_shape
  int c_shape_status;       /* 0=dead, 1=alive */
  struct dia_shape * c_shape;

- Add a field in `struct dia_shape' that points to its `struct
  dia_guile_shape' if it has one, so that C code can update the
  c_shape_status field when the underlying shape is deleted.

- Turn `struct dia_guile_shape' into a SMOB type - see node `Defining
  New Types (Smobs)' in the reference manual.

- Whenever you need to represent a C shape onto the Scheme level,
  create a SMOB instance for it, and pass that.

- In primitive code that receives a shape SMOB instance, check the
  c_shape_status field when decoding it, to find out whether the
  underlying C shape is still there.

Once these details of object representation are decided, writing the
rest of the primitive function code should be pretty straightforward.
All that then remains is to export the primitives to Scheme by calling
the `scm_c_define_gsubr' function.

Finally, what does the overall structure look like?

Assuming that Dia currently looks like this:

- main ()
  - do lots of initialization and setup stuff
  - enter Gtk main loop

the simplest thing is to change it to look like this:

- main ()
  - do lots of initialization and setup stuff
  - scm_boot_guile (argc, argv, inner_main, NULL)

- inner_main ()
  - define all SMOB types
  - export primitives to Scheme using scm_c_define_gsubr
  - enter Gtk main loop

OK, there's lots more that one could say, but let me know if this is
any help so far.


reply via email to

[Prev in Thread] Current Thread [Next in Thread]