mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-06-13 15:10:34 +02:00
Updated for new scm_is_bool, scm_is_true, etc.
This commit is contained in:
parent
cd2825a8e0
commit
5f7fa54d98
2 changed files with 1 additions and 783 deletions
|
@ -904,7 +904,7 @@ Use @code{SCM_DEFER_INTS} and @code{SCM_ALLOW_INTS} instead. Note that
|
||||||
these macros are used without parentheses, as in @code{SCM_DEFER_INTS;}.
|
these macros are used without parentheses, as in @code{SCM_DEFER_INTS;}.
|
||||||
|
|
||||||
@item @code{gh_bool2scm}
|
@item @code{gh_bool2scm}
|
||||||
Use @code{SCM_BOOL} instead.
|
Use @code{scm_from_bool} instead.
|
||||||
|
|
||||||
@item @code{gh_ulong2scm}
|
@item @code{gh_ulong2scm}
|
||||||
Use @code{scm_ulong2num} instead.
|
Use @code{scm_ulong2num} instead.
|
||||||
|
|
|
@ -1,782 +0,0 @@
|
||||||
@c -*-texinfo-*-
|
|
||||||
@c This is part of the GNU Guile Reference Manual.
|
|
||||||
@c Copyright (C) 1996, 1997, 2000, 2001, 2002, 2003, 2004
|
|
||||||
@c Free Software Foundation, Inc.
|
|
||||||
@c See the file guile.texi for copying conditions.
|
|
||||||
|
|
||||||
@page
|
|
||||||
@node Programming Overview
|
|
||||||
@section An Overview of Guile Programming
|
|
||||||
|
|
||||||
Guile is designed as an extension language interpreter that is
|
|
||||||
straightforward to integrate with applications written in C (and C++).
|
|
||||||
The big win here for the application developer is that Guile
|
|
||||||
integration, as the Guile web page says, ``lowers your project's
|
|
||||||
hacktivation energy.'' Lowering the hacktivation energy means that you,
|
|
||||||
as the application developer, @emph{and your users}, reap the benefits
|
|
||||||
that flow from being able to extend the application in a high level
|
|
||||||
extension language rather than in plain old C.
|
|
||||||
|
|
||||||
In abstract terms, it's difficult to explain what this really means and
|
|
||||||
what the integration process involves, so instead let's begin by jumping
|
|
||||||
straight into an example of how you might integrate Guile into an
|
|
||||||
existing program, and what you could expect to gain by so doing. With
|
|
||||||
that example under our belts, we'll then return to a more general
|
|
||||||
analysis of the arguments involved and the range of programming options
|
|
||||||
available.
|
|
||||||
|
|
||||||
@menu
|
|
||||||
* Extending Dia:: How one might extend Dia using Guile.
|
|
||||||
* Scheme vs C:: Why Scheme is more hackable than C.
|
|
||||||
* Testbed Example:: Example: using Guile in a testbed.
|
|
||||||
* Programming Options:: Options for Guile programming.
|
|
||||||
* User Programming:: How about application users?
|
|
||||||
@end menu
|
|
||||||
|
|
||||||
|
|
||||||
@node Extending Dia
|
|
||||||
@subsection How One Might Extend Dia Using Guile
|
|
||||||
|
|
||||||
Dia is a free software program for drawing schematic diagrams like flow
|
|
||||||
charts and floor plans (REFFIXME). This section conducts the thought
|
|
||||||
experiment of adding Guile to Dia. In so doing, it aims to illustrate
|
|
||||||
several of the steps and considerations involved in adding Guile to
|
|
||||||
applications in general.
|
|
||||||
|
|
||||||
@menu
|
|
||||||
* Dia Objective:: Deciding why you want to add Guile.
|
|
||||||
* Dia Steps:: Four steps required to add Guile.
|
|
||||||
* Dia Smobs:: How to represent Dia data in Scheme.
|
|
||||||
* Dia Primitives:: Writing Guile primitives for Dia.
|
|
||||||
* Dia Hook:: Providing a hook for Scheme evaluation.
|
|
||||||
* Dia Structure:: Overall structure for adding Guile.
|
|
||||||
* Dia Advanced:: Going further with Dia and Guile.
|
|
||||||
@end menu
|
|
||||||
|
|
||||||
|
|
||||||
@node Dia Objective
|
|
||||||
@subsubsection Deciding Why You Want to Add Guile
|
|
||||||
|
|
||||||
First off, you should understand why you want to add Guile to Dia at
|
|
||||||
all, and that means forming a picture of what Dia does and how it does
|
|
||||||
it. So, what are the constituents of the Dia application?
|
|
||||||
|
|
||||||
@itemize @bullet
|
|
||||||
@item
|
|
||||||
Most importantly, the @dfn{application domain objects} --- in other
|
|
||||||
words, the concepts that differentiate Dia from another application such
|
|
||||||
as a word processor or spreadsheet: shapes, templates, connectors,
|
|
||||||
pages, plus the properties of all these things.
|
|
||||||
|
|
||||||
@item
|
|
||||||
The code that manages the graphical face of the application, including
|
|
||||||
the layout and display of the objects above.
|
|
||||||
|
|
||||||
@item
|
|
||||||
The code that handles input events, which indicate that the application
|
|
||||||
user is wanting to do something.
|
|
||||||
@end itemize
|
|
||||||
|
|
||||||
@noindent
|
|
||||||
(In other words, a textbook example of the @dfn{model - view -
|
|
||||||
controller} paradigm.)
|
|
||||||
|
|
||||||
Next question: how will Dia benefit once the Guile integration is
|
|
||||||
complete? Several (positive!) answers are possible here, and the choice
|
|
||||||
is obviously up to the application developers. Still, one answer is
|
|
||||||
that the main benefit will be the ability to manipulate Dia's
|
|
||||||
application domain objects from Scheme.
|
|
||||||
|
|
||||||
Suppose that Dia made a set of procedures available in Scheme,
|
|
||||||
representing the most basic operations on objects such as shapes,
|
|
||||||
connectors, and so on. Using Scheme, the application user could then
|
|
||||||
write code that builds upon these basic operations to create more
|
|
||||||
complex procedures. For example, given basic procedures to enumerate
|
|
||||||
the objects on a page, to determine whether an object is a square, and
|
|
||||||
to change the fill pattern of a single shape, the user can write a
|
|
||||||
Scheme procedure to change the fill pattern of all squares on the
|
|
||||||
current page:
|
|
||||||
|
|
||||||
@lisp
|
|
||||||
(define (change-squares'-fill-pattern new-pattern)
|
|
||||||
(for-each-shape current-page
|
|
||||||
(lambda (shape)
|
|
||||||
(if (square? shape)
|
|
||||||
(change-fill-pattern shape new-pattern)))))
|
|
||||||
@end lisp
|
|
||||||
|
|
||||||
|
|
||||||
@node Dia Steps
|
|
||||||
@subsubsection Four Steps Required to Add Guile
|
|
||||||
|
|
||||||
Assuming this objective, four steps are needed to achieve it.
|
|
||||||
|
|
||||||
First, you need a way of representing your application-specific objects
|
|
||||||
--- such as @code{shape} in the previous example --- when they are
|
|
||||||
passed into the Scheme world. Unless your objects are so simple that
|
|
||||||
they map naturally into builtin Scheme data types like numbers and
|
|
||||||
strings, you will probably want to use Guile's @dfn{SMOB} interface to
|
|
||||||
create a new Scheme data type for your objects.
|
|
||||||
|
|
||||||
Second, you need to write code for the basic operations like
|
|
||||||
@code{for-each-shape} and @code{square?} such that they access and
|
|
||||||
manipulate your existing data structures correctly, and then make these
|
|
||||||
operations available as @dfn{primitives} on the Scheme level.
|
|
||||||
|
|
||||||
Third, you need to provide some mechanism within the Dia application
|
|
||||||
that a user can hook into to cause arbitrary Scheme code to be
|
|
||||||
evaluated.
|
|
||||||
|
|
||||||
Finally, you need to restructure your top-level application C code a
|
|
||||||
little so that it initializes the Guile interpreter correctly and
|
|
||||||
declares your @dfn{SMOBs} and @dfn{primitives} to the Scheme world.
|
|
||||||
|
|
||||||
The following subsections expand on these four points in turn.
|
|
||||||
|
|
||||||
|
|
||||||
@node Dia Smobs
|
|
||||||
@subsubsection How to Represent Dia Data in Scheme
|
|
||||||
|
|
||||||
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, let's look again at the example we gave
|
|
||||||
earlier of how application users can use Guile to build higher-level
|
|
||||||
functions from the primitives that Dia itself provides.
|
|
||||||
|
|
||||||
@lisp
|
|
||||||
(define (change-squares'-fill-pattern new-pattern)
|
|
||||||
(for-each-shape current-page
|
|
||||||
(lambda (shape)
|
|
||||||
(if (square? shape)
|
|
||||||
(change-fill-pattern shape new-pattern)))))
|
|
||||||
@end lisp
|
|
||||||
|
|
||||||
Consider what is stored here in the variable @code{shape}. For each
|
|
||||||
shape on the current page, the @code{for-each-shape} primitive calls
|
|
||||||
@code{(lambda (shape) @dots{})} with an argument representing that
|
|
||||||
shape. Question is: how is that argument represented on the Scheme
|
|
||||||
level? The issues are as follows.
|
|
||||||
|
|
||||||
@itemize @bullet
|
|
||||||
@item
|
|
||||||
Whatever the representation, it has to be decodable again by the C code
|
|
||||||
for the @code{square?} and @code{change-fill-pattern} primitives. In
|
|
||||||
other words, a primitive like @code{square?} has somehow to be able to
|
|
||||||
turn the value that it receives back into something that points to the
|
|
||||||
underlying C structure describing a shape.
|
|
||||||
|
|
||||||
@item
|
|
||||||
The representation must also cope with Scheme code holding on to the
|
|
||||||
value for later use. What happens if the Scheme code stores
|
|
||||||
@code{shape} in a global variable, but then that shape is deleted (in a
|
|
||||||
way that the Scheme code is not aware of), and later on some other
|
|
||||||
Scheme code uses that global variable again in a call to, say,
|
|
||||||
@code{square?}?
|
|
||||||
|
|
||||||
@item
|
|
||||||
The lifetime and memory allocation of objects that exist @emph{only} in
|
|
||||||
the Scheme world is managed automatically by Guile's garbage collector
|
|
||||||
using one simple rule: when there are no remaining references to an
|
|
||||||
object, the object is considered dead and so its memory is freed. But
|
|
||||||
for objects that exist in both C and Scheme, the picture is more
|
|
||||||
complicated; in the case of Dia, where the @code{shape} argument passes
|
|
||||||
transiently in and out of the Scheme world, it would be quite wrong the
|
|
||||||
@strong{delete} the underlying C shape just because the Scheme code has
|
|
||||||
finished evaluation. How do we avoid this happening?
|
|
||||||
@end itemize
|
|
||||||
|
|
||||||
One resolution of these issues is for the Scheme-level representation of
|
|
||||||
a shape to be a new, Scheme-specific C structure wrapped up as a SMOB.
|
|
||||||
The SMOB is what is passed into and out of Scheme code, and the
|
|
||||||
Scheme-specific C structure inside the SMOB points to Dia's underlying C
|
|
||||||
structure so that the code for primitives like @code{square?} can get at
|
|
||||||
it.
|
|
||||||
|
|
||||||
To cope with an underlying shape being deleted while Scheme code is
|
|
||||||
still holding onto a Scheme shape value, the underlying C structure
|
|
||||||
should have a new field that points to the Scheme-specific SMOB. When a
|
|
||||||
shape is deleted, the relevant code chains through to the
|
|
||||||
Scheme-specific structure and sets its pointer back to the underlying
|
|
||||||
structure to NULL. Thus the SMOB value for the shape continues to
|
|
||||||
exist, but any primitive code that tries to use it will detect that the
|
|
||||||
underlying shape has been deleted because the underlying structure
|
|
||||||
pointer is NULL.
|
|
||||||
|
|
||||||
So, to summarize the steps involved in this resolution of the problem
|
|
||||||
(and assuming that the underlying C structure for a shape is
|
|
||||||
@code{struct dia_shape}):
|
|
||||||
|
|
||||||
@itemize @bullet
|
|
||||||
@item
|
|
||||||
Define a new Scheme-specific structure that @emph{points} to the
|
|
||||||
underlying C structure:
|
|
||||||
|
|
||||||
@lisp
|
|
||||||
struct dia_guile_shape
|
|
||||||
@{
|
|
||||||
struct dia_shape * c_shape; /* NULL => deleted */
|
|
||||||
@}
|
|
||||||
@end lisp
|
|
||||||
|
|
||||||
@item
|
|
||||||
Add a field to @code{struct dia_shape} that points to its @code{struct
|
|
||||||
dia_guile_shape} if it has one ---
|
|
||||||
|
|
||||||
@lisp
|
|
||||||
struct dia_shape
|
|
||||||
@{
|
|
||||||
@dots{}
|
|
||||||
struct dia_guile_shape * guile_shape;
|
|
||||||
@}
|
|
||||||
@end lisp
|
|
||||||
|
|
||||||
@noindent
|
|
||||||
--- so that C code can set @code{guile_shape->c_shape} to NULL when the
|
|
||||||
underlying shape is deleted.
|
|
||||||
|
|
||||||
@item
|
|
||||||
Wrap @code{struct dia_guile_shape} as a SMOB type.
|
|
||||||
|
|
||||||
@item
|
|
||||||
Whenever you need to represent a C shape onto the Scheme level, create a
|
|
||||||
SMOB instance for it, and pass that.
|
|
||||||
|
|
||||||
@item
|
|
||||||
In primitive code that receives a shape SMOB instance, check the
|
|
||||||
@code{c_shape} field when decoding it, to find out whether the
|
|
||||||
underlying C shape is still there.
|
|
||||||
@end itemize
|
|
||||||
|
|
||||||
As far as memory management is concerned, the SMOB values and their
|
|
||||||
Scheme-specific structures are under the control of the garbage
|
|
||||||
collector, whereas the underlying C structures are explicitly managed in
|
|
||||||
exactly the same way that Dia managed them before we thought of adding
|
|
||||||
Guile.
|
|
||||||
|
|
||||||
When the garbage collector decides to free a shape SMOB value, it calls
|
|
||||||
the @dfn{SMOB free} function that was specified when defining the shape
|
|
||||||
SMOB type. To maintain the correctness of the @code{guile_shape} field
|
|
||||||
in the underlying C structure, this function should chain through to the
|
|
||||||
underlying C structure (if it still exists) and set its
|
|
||||||
@code{guile_shape} field to NULL.
|
|
||||||
|
|
||||||
For full documentation on defining and using SMOB types, see
|
|
||||||
@ref{Defining New Types (Smobs)}.
|
|
||||||
|
|
||||||
|
|
||||||
@node Dia Primitives
|
|
||||||
@subsubsection Writing Guile Primitives for Dia
|
|
||||||
|
|
||||||
Once the details of object representation are decided, writing the
|
|
||||||
primitive function code that you need is usually straightforward.
|
|
||||||
|
|
||||||
A primitive is simply a C function whose arguments and return value are
|
|
||||||
all of type @code{SCM}, and whose body does whatever you want it to do.
|
|
||||||
As an example, here is a possible implementation of the @code{square?}
|
|
||||||
primitive:
|
|
||||||
|
|
||||||
@lisp
|
|
||||||
#define FUNC_NAME "square?"
|
|
||||||
static SCM square_p (SCM shape)
|
|
||||||
@{
|
|
||||||
struct dia_guile_shape * guile_shape;
|
|
||||||
|
|
||||||
/* Check that arg is really a shape SMOB. */
|
|
||||||
SCM_VALIDATE_SHAPE (SCM_ARG1, shape);
|
|
||||||
|
|
||||||
/* Access Scheme-specific shape structure. */
|
|
||||||
guile_shape = SCM_SMOB_DATA (shape);
|
|
||||||
|
|
||||||
/* Find out if underlying shape exists and is a
|
|
||||||
square; return answer as a Scheme boolean. */
|
|
||||||
return SCM_BOOL (guile_shape->c_shape &&
|
|
||||||
(guile_shape->c_shape->type == DIA_SQUARE));
|
|
||||||
@}
|
|
||||||
#undef FUNC_NAME
|
|
||||||
@end lisp
|
|
||||||
|
|
||||||
Notice how easy it is to chain through from the @code{SCM shape}
|
|
||||||
parameter that @code{square_p} receives --- which is a SMOB --- to the
|
|
||||||
Scheme-specific structure inside the SMOB, and thence to the underlying
|
|
||||||
C structure for the shape.
|
|
||||||
|
|
||||||
In this code, @code{SCM_SMOB_DATA} and @code{SCM_BOOL} are macros from
|
|
||||||
the standard Guile API. @code{SCM_VALIDATE_SHAPE} is a macro that you
|
|
||||||
should define as part of your SMOB definition: it checks that the passed
|
|
||||||
parameter is of the expected type. This is needed to guard against
|
|
||||||
Scheme code using the @code{square?} procedure incorrectly, as in
|
|
||||||
@code{(square? "hello")}; Scheme's latent typing means that usage errors
|
|
||||||
like this must be caught at run time.
|
|
||||||
|
|
||||||
Having written the C code for your primitives, you need to make them
|
|
||||||
available as Scheme procedures by calling the @code{scm_c_define_gsubr}
|
|
||||||
function. @code{scm_c_define_gsubr} (REFFIXME) takes arguments that
|
|
||||||
specify the Scheme-level name for the primitive and how many required,
|
|
||||||
optional and rest arguments it can accept. The @code{square?} primitive
|
|
||||||
always requires exactly one argument, so the call to make it available
|
|
||||||
in Scheme reads like this:
|
|
||||||
|
|
||||||
@lisp
|
|
||||||
scm_c_define_gsubr ("square?", 1, 0, 0, square_p);
|
|
||||||
@end lisp
|
|
||||||
|
|
||||||
For where to put this call, see the subsection after next on the
|
|
||||||
structure of Guile-enabled code (@pxref{Dia Structure}).
|
|
||||||
|
|
||||||
|
|
||||||
@node Dia Hook
|
|
||||||
@subsubsection Providing a Hook for the Evaluation of Scheme Code
|
|
||||||
|
|
||||||
To make the Guile integration useful, you have to design some kind of
|
|
||||||
hook into your application that application users can use to cause their
|
|
||||||
Scheme code to be evaluated.
|
|
||||||
|
|
||||||
Technically, this is straightforward; you just have to decide on a
|
|
||||||
mechanism that is appropriate for your application. Think of Emacs, for
|
|
||||||
example: when you type @kbd{@key{ESC} :}, you get a prompt where you can
|
|
||||||
type in any Elisp code, which Emacs will then evaluate. Or, again like
|
|
||||||
Emacs, you could provide a mechanism (such as an init file) to allow
|
|
||||||
Scheme code to be associated with a particular key sequence, and
|
|
||||||
evaluate the code when that key sequence is entered.
|
|
||||||
|
|
||||||
In either case, once you have the Scheme code that you want to evaluate,
|
|
||||||
as a null terminated string, you can tell Guile to evaluate it by
|
|
||||||
calling the @code{scm_c_eval_string} function.
|
|
||||||
|
|
||||||
|
|
||||||
@node Dia Structure
|
|
||||||
@subsubsection Top-level Structure of Guile-enabled Dia
|
|
||||||
|
|
||||||
Let's assume that the pre-Guile Dia code looks structurally like this:
|
|
||||||
|
|
||||||
@itemize @bullet
|
|
||||||
@item
|
|
||||||
@code{main ()}
|
|
||||||
|
|
||||||
@itemize @bullet
|
|
||||||
@item
|
|
||||||
do lots of initialization and setup stuff
|
|
||||||
@item
|
|
||||||
enter Gtk main loop
|
|
||||||
@end itemize
|
|
||||||
@end itemize
|
|
||||||
|
|
||||||
When you add Guile to a program, one (rather technical) requirement is
|
|
||||||
that Guile's garbage collector needs to know where the bottom of the C
|
|
||||||
stack is. The easiest way to ensure this is to use
|
|
||||||
@code{scm_boot_guile} like this:
|
|
||||||
|
|
||||||
@itemize @bullet
|
|
||||||
@item
|
|
||||||
@code{main ()}
|
|
||||||
|
|
||||||
@itemize @bullet
|
|
||||||
@item
|
|
||||||
do lots of initialization and setup stuff
|
|
||||||
@item
|
|
||||||
@code{scm_boot_guile (argc, argv, inner_main, NULL)}
|
|
||||||
@end itemize
|
|
||||||
|
|
||||||
@item
|
|
||||||
@code{inner_main ()}
|
|
||||||
|
|
||||||
@itemize @bullet
|
|
||||||
@item
|
|
||||||
define all SMOB types
|
|
||||||
@item
|
|
||||||
export primitives to Scheme using @code{scm_c_define_gsubr}
|
|
||||||
@item
|
|
||||||
enter Gtk main loop
|
|
||||||
@end itemize
|
|
||||||
@end itemize
|
|
||||||
|
|
||||||
In other words, you move the guts of what was previously in your
|
|
||||||
@code{main} function into a new function called @code{inner_main}, and
|
|
||||||
then add a @code{scm_boot_guile} call, with @code{inner_main} as a
|
|
||||||
parameter, to the end of @code{main}.
|
|
||||||
|
|
||||||
Assuming that you are using SMOBs and have written primitive code as
|
|
||||||
described in the preceding subsections, you also need to insert calls to
|
|
||||||
declare your new SMOBs and export the primitives to Scheme. These
|
|
||||||
declarations must happen @emph{inside} the dynamic scope of the
|
|
||||||
@code{scm_boot_guile} call, but also @emph{before} any code is run that
|
|
||||||
could possibly use them --- the beginning of @code{inner_main} is an
|
|
||||||
ideal place for this.
|
|
||||||
|
|
||||||
|
|
||||||
@node Dia Advanced
|
|
||||||
@subsubsection Going Further with Dia and Guile
|
|
||||||
|
|
||||||
The steps described so far implement an initial Guile integration that
|
|
||||||
already gives a lot of additional power to Dia application users. But
|
|
||||||
there are further steps that you could take, and it's interesting to
|
|
||||||
consider a few of these.
|
|
||||||
|
|
||||||
In general, you could progressively move more of Dia's source code from
|
|
||||||
C into Scheme. This might make the code more maintainable and
|
|
||||||
extensible, and it could open the door to new programming paradigms that
|
|
||||||
are tricky to effect in C but straightforward in Scheme.
|
|
||||||
|
|
||||||
A specific example of this is that you could use the guile-gtk package,
|
|
||||||
which provides Scheme-level procedures for most of the Gtk+ library, to
|
|
||||||
move the code that lays out and displays Dia objects from C to Scheme.
|
|
||||||
|
|
||||||
As you follow this path, it naturally becomes less useful to maintain a
|
|
||||||
distinction between Dia's original non-Guile-related source code, and
|
|
||||||
its later code implementing SMOBs and primitives for the Scheme world.
|
|
||||||
|
|
||||||
For example, suppose that the original source code had a
|
|
||||||
@code{dia_change_fill_pattern} function:
|
|
||||||
|
|
||||||
@lisp
|
|
||||||
void dia_change_fill_pattern (struct dia_shape * shape,
|
|
||||||
struct dia_pattern * pattern)
|
|
||||||
@{
|
|
||||||
/* real pattern change work */
|
|
||||||
@}
|
|
||||||
@end lisp
|
|
||||||
|
|
||||||
During initial Guile integration, you add a @code{change_fill_pattern}
|
|
||||||
primitive for Scheme purposes, which accesses the underlying structures
|
|
||||||
from its SMOB values and uses @code{dia_change_fill_pattern} to do the
|
|
||||||
real work:
|
|
||||||
|
|
||||||
@lisp
|
|
||||||
SCM change_fill_pattern (SCM shape, SCM pattern)
|
|
||||||
@{
|
|
||||||
struct dia_shape * d_shape;
|
|
||||||
struct dia_pattern * d_pattern;
|
|
||||||
|
|
||||||
@dots{}
|
|
||||||
|
|
||||||
dia_change_fill_pattern (d_shape, d_pattern);
|
|
||||||
|
|
||||||
return SCM_UNSPECIFIED;
|
|
||||||
@}
|
|
||||||
@end lisp
|
|
||||||
|
|
||||||
At this point, it makes sense to keep @code{dia_change_fill_pattern} and
|
|
||||||
@code{change_fill_pattern} separate, because
|
|
||||||
@code{dia_change_fill_pattern} can also be called without going through
|
|
||||||
Scheme at all, say because the user clicks a button which causes a
|
|
||||||
C-registered Gtk+ callback to be called.
|
|
||||||
|
|
||||||
But, if the code for creating buttons and registering their callbacks is
|
|
||||||
moved into Scheme (using guile-gtk), it may become true that
|
|
||||||
@code{dia_change_fill_pattern} can no longer be called other than
|
|
||||||
through Scheme. In which case, it makes sense to abolish it and move
|
|
||||||
its contents directly into @code{change_fill_pattern}, like this:
|
|
||||||
|
|
||||||
@lisp
|
|
||||||
SCM change_fill_pattern (SCM shape, SCM pattern)
|
|
||||||
@{
|
|
||||||
struct dia_shape * d_shape;
|
|
||||||
struct dia_pattern * d_pattern;
|
|
||||||
|
|
||||||
@dots{}
|
|
||||||
|
|
||||||
/* real pattern change work */
|
|
||||||
|
|
||||||
return SCM_UNSPECIFIED;
|
|
||||||
@}
|
|
||||||
@end lisp
|
|
||||||
|
|
||||||
So further Guile integration progressively @emph{reduces} the amount of
|
|
||||||
functional C code that you have to maintain over the long term.
|
|
||||||
|
|
||||||
A similar argument applies to data representation. In the discussion of
|
|
||||||
SMOBs earlier, issues arose because of the different memory management
|
|
||||||
and lifetime models that normally apply to data structures in C and in
|
|
||||||
Scheme. However, with further Guile integration, you can resolve this
|
|
||||||
issue in a more radical way by allowing all your data structures to be
|
|
||||||
under the control of the garbage collector, and kept alive by references
|
|
||||||
from the Scheme world. Instead of maintaining an array or linked list
|
|
||||||
of shapes in C, you would instead maintain a list in Scheme.
|
|
||||||
|
|
||||||
Rather like the coalescing of @code{dia_change_fill_pattern} and
|
|
||||||
@code{change_fill_pattern}, the practical upshot of such a change is
|
|
||||||
that you would no longer have to keep the @code{dia_shape} and
|
|
||||||
@code{dia_guile_shape} structures separate, and so wouldn't need to
|
|
||||||
worry about the pointers between them. Instead, you could change the
|
|
||||||
SMOB definition to wrap the @code{dia_shape} structure directly, and
|
|
||||||
send @code{dia_guile_shape} off to the scrap yard. Cut out the middle
|
|
||||||
man!
|
|
||||||
|
|
||||||
Finally, we come to the holy grail of Guile's free software / extension
|
|
||||||
language approach. Once you have a Scheme representation for
|
|
||||||
interesting Dia data types like shapes, and a handy bunch of primitives
|
|
||||||
for manipulating them, it suddenly becomes clear that you have a bundle
|
|
||||||
of functionality that could have far-ranging use beyond Dia itself. In
|
|
||||||
other words, the data types and primitives could now become a library,
|
|
||||||
and Dia becomes just one of the many possible applications using that
|
|
||||||
library --- albeit, at this early stage, a rather important one!
|
|
||||||
|
|
||||||
In this model, Guile becomes just the glue that binds everything
|
|
||||||
together. Imagine an application that usefully combined functionality
|
|
||||||
from Dia, Gnumeric and GnuCash --- it's tricky right now, because no
|
|
||||||
such application yet exists; but it'll happen some day @dots{}
|
|
||||||
|
|
||||||
|
|
||||||
@node Scheme vs C
|
|
||||||
@subsection Why Scheme is More Hackable Than C
|
|
||||||
|
|
||||||
Underlying Guile's value proposition is the assumption that programming
|
|
||||||
in a high level language, specifically Guile's implementation of Scheme,
|
|
||||||
is necessarily better in some way than programming in C. What do we
|
|
||||||
mean by this claim, and how can we be so sure?
|
|
||||||
|
|
||||||
One class of advantages applies not only to Scheme, but more generally
|
|
||||||
to any interpretable, high level, scripting language, such as Emacs
|
|
||||||
Lisp, Python, Ruby, or @TeX{}'s macro language. Common features of all
|
|
||||||
such languages, when compared to C, are that:
|
|
||||||
|
|
||||||
@itemize @bullet
|
|
||||||
@item
|
|
||||||
They lend themselves to rapid and experimental development cycles,
|
|
||||||
owing usually to a combination of their interpretability and the
|
|
||||||
integrated development environment in which they are used.
|
|
||||||
|
|
||||||
@item
|
|
||||||
They free developers from some of the low level bookkeeping tasks
|
|
||||||
associated with C programming, notably memory management.
|
|
||||||
|
|
||||||
@item
|
|
||||||
They provide high level features such as container objects and exception
|
|
||||||
handling that make common programming tasks easier.
|
|
||||||
@end itemize
|
|
||||||
|
|
||||||
In the case of Scheme, particular features that make programming easier
|
|
||||||
--- and more fun! --- are its powerful mechanisms for abstracting parts
|
|
||||||
of programs (closures --- @pxref{About Closure}) and for iteration
|
|
||||||
(@pxref{while do}).
|
|
||||||
|
|
||||||
The evidence in support of this argument is empirical: the huge amount
|
|
||||||
of code that has been written in extension languages for applications
|
|
||||||
that support this mechanism. Most notable are extensions written in
|
|
||||||
Emacs Lisp for GNU Emacs, in @TeX{}'s macro language for @TeX{}, and in
|
|
||||||
Script-Fu for the Gimp, but there is increasingly now a significant code
|
|
||||||
eco-system for Guile-based applications as well, such as Lilypond and
|
|
||||||
GnuCash. It is close to inconceivable that similar amounts of
|
|
||||||
functionality could have been added to these applications just by
|
|
||||||
writing new code in their base implementation languages.
|
|
||||||
|
|
||||||
|
|
||||||
@node Testbed Example
|
|
||||||
@subsection Example: Using Guile for an Application Testbed
|
|
||||||
|
|
||||||
As an example of what this means in practice, imagine writing a testbed
|
|
||||||
for an application that is tested by submitting various requests (via a
|
|
||||||
C interface) and validating the output received. Suppose further that
|
|
||||||
the application keeps an idea of its current state, and that the
|
|
||||||
``correct'' output for a given request may depend on the current
|
|
||||||
application state. A complete ``white box''@footnote{A @dfn{white box}
|
|
||||||
test plan is one that incorporates knowledge of the internal design of
|
|
||||||
the application under test.} test plan for this application would aim to
|
|
||||||
submit all possible requests in each distinguishable state, and validate
|
|
||||||
the output for all request/state combinations.
|
|
||||||
|
|
||||||
To write all this test code in C would be very tedious. Suppose instead
|
|
||||||
that the testbed code adds a single new C function, to submit an
|
|
||||||
arbitrary request and return the response, and then uses Guile to export
|
|
||||||
this function as a Scheme procedure. The rest of the testbed can then
|
|
||||||
be written in Scheme, and so benefits from all the advantages of
|
|
||||||
programming in Scheme that were described in the previous section.
|
|
||||||
|
|
||||||
(In this particular example, there is an additional benefit of writing
|
|
||||||
most of the testbed in Scheme. A common problem for white box testing
|
|
||||||
is that mistakes and mistaken assumptions in the application under test
|
|
||||||
can easily be reproduced in the testbed code. It is more difficult to
|
|
||||||
copy mistakes like this when the testbed is written in a different
|
|
||||||
language from the application.)
|
|
||||||
|
|
||||||
|
|
||||||
@node Programming Options
|
|
||||||
@subsection A Choice of Programming Options
|
|
||||||
|
|
||||||
The preceding arguments and example point to a model of Guile
|
|
||||||
programming that is applicable in many cases. According to this model,
|
|
||||||
Guile programming involves a balance between C and Scheme programming,
|
|
||||||
with the aim being to extract the greatest possible Scheme level benefit
|
|
||||||
from the least amount of C level work.
|
|
||||||
|
|
||||||
The C level work required in this model usually consists of packaging
|
|
||||||
and exporting functions and application objects such that they can be
|
|
||||||
seen and manipulated on the Scheme level. To help with this, Guile's C
|
|
||||||
language interface includes utility features that aim to make this kind
|
|
||||||
of integration very easy for the application developer. These features
|
|
||||||
are documented later in this part of the manual: see REFFIXME.
|
|
||||||
|
|
||||||
This model, though, is really just one of a range of possible
|
|
||||||
programming options. If all of the functionality that you need is
|
|
||||||
available from Scheme, you could choose instead to write your whole
|
|
||||||
application in Scheme (or one of the other high level languages that
|
|
||||||
Guile supports through translation), and simply use Guile as an
|
|
||||||
interpreter for Scheme. (In the future, we hope that Guile will also be
|
|
||||||
able to compile Scheme code, so lessening the performance gap between C
|
|
||||||
and Scheme code.) Or, at the other end of the C--Scheme scale, you
|
|
||||||
could write the majority of your application in C, and only call out to
|
|
||||||
Guile occasionally for specific actions such as reading a configuration
|
|
||||||
file or executing a user-specified extension. The choices boil down to
|
|
||||||
two basic questions:
|
|
||||||
|
|
||||||
@itemize @bullet
|
|
||||||
@item
|
|
||||||
Which parts of the application do you write in C, and which in Scheme
|
|
||||||
(or another high level translated language)?
|
|
||||||
|
|
||||||
@item
|
|
||||||
How do you design the interface between the C and Scheme parts of your
|
|
||||||
application?
|
|
||||||
@end itemize
|
|
||||||
|
|
||||||
These are of course design questions, and the right design for any given
|
|
||||||
application will always depend upon the particular requirements that you
|
|
||||||
are trying to meet. In the context of Guile, however, there are some
|
|
||||||
generally applicable considerations that can help you when designing
|
|
||||||
your answers.
|
|
||||||
|
|
||||||
@menu
|
|
||||||
* Available Functionality:: What functionality is already available?
|
|
||||||
* Basic Constraints:: Functional and performance constraints.
|
|
||||||
* Style Choices:: Your preferred programming style.
|
|
||||||
* Program Control:: What controls program execution?
|
|
||||||
@end menu
|
|
||||||
|
|
||||||
|
|
||||||
@node Available Functionality
|
|
||||||
@subsubsection What Functionality is Already Available?
|
|
||||||
|
|
||||||
Suppose, for the sake of argument, that you would prefer to write your
|
|
||||||
whole application in Scheme. Then the API available to you consists of:
|
|
||||||
|
|
||||||
@itemize @bullet
|
|
||||||
@item
|
|
||||||
standard Scheme
|
|
||||||
|
|
||||||
@item
|
|
||||||
plus the extensions to standard Scheme provided by
|
|
||||||
Guile in its core distribution
|
|
||||||
|
|
||||||
@item
|
|
||||||
plus any additional functionality that you or others have packaged so
|
|
||||||
that it can be loaded as a Guile Scheme module.
|
|
||||||
@end itemize
|
|
||||||
|
|
||||||
A module in the last category can either be a pure Scheme module --- in
|
|
||||||
other words a collection of utility procedures coded in Scheme --- or a
|
|
||||||
module that provides a Scheme interface to an extension library coded in
|
|
||||||
C --- in other words a nice package where someone else has done the work
|
|
||||||
of wrapping up some useful C code for you. The set of available modules
|
|
||||||
is growing quickly and already includes such useful examples as
|
|
||||||
@code{(gtk gtk)}, which makes Gtk+ drawing functions available in
|
|
||||||
Scheme, and @code{(database postgres)}, which provides SQL access to a
|
|
||||||
Postgres database.
|
|
||||||
|
|
||||||
Given the growing collection of pre-existing modules, it is quite
|
|
||||||
feasible that your application could be implemented by combining a
|
|
||||||
selection of these modules together with new application code written in
|
|
||||||
Scheme.
|
|
||||||
|
|
||||||
If this approach is not enough, because the functionality that your
|
|
||||||
application needs is not already available in this form, and it is
|
|
||||||
impossible to write the new functionality in Scheme, you will need to
|
|
||||||
write some C code. If the required function is already available in C
|
|
||||||
(e.g. in a library), all you need is a little glue to connect it to the
|
|
||||||
world of Guile. If not, you need both to write the basic code and to
|
|
||||||
plumb it into Guile.
|
|
||||||
|
|
||||||
In either case, two general considerations are important. Firstly, what
|
|
||||||
is the interface by which the functionality is presented to the Scheme
|
|
||||||
world? Does the interface consist only of function calls (for example,
|
|
||||||
a simple drawing interface), or does it need to include @dfn{objects} of
|
|
||||||
some kind that can be passed between C and Scheme and manipulated by
|
|
||||||
both worlds. Secondly, how does the lifetime and memory management of
|
|
||||||
objects in the C code relate to the garbage collection governed approach
|
|
||||||
of Scheme objects? In the case where the basic C code is not already
|
|
||||||
written, most of the difficulties of memory management can be avoided by
|
|
||||||
using Guile's C interface features from the start.
|
|
||||||
|
|
||||||
For the full documentation on writing C code for Guile and connecting
|
|
||||||
existing C code to the Guile world, see REFFIXME.
|
|
||||||
|
|
||||||
|
|
||||||
@node Basic Constraints
|
|
||||||
@subsubsection Functional and Performance Constraints
|
|
||||||
|
|
||||||
|
|
||||||
@node Style Choices
|
|
||||||
@subsubsection Your Preferred Programming Style
|
|
||||||
|
|
||||||
|
|
||||||
@node Program Control
|
|
||||||
@subsubsection What Controls Program Execution?
|
|
||||||
|
|
||||||
|
|
||||||
@node User Programming
|
|
||||||
@subsection How About Application Users?
|
|
||||||
|
|
||||||
So far we have considered what Guile programming means for an
|
|
||||||
application developer. But what if you are instead @emph{using} an
|
|
||||||
existing Guile-based application, and want to know what your
|
|
||||||
options are for programming and extending this application?
|
|
||||||
|
|
||||||
The answer to this question varies from one application to another,
|
|
||||||
because the options available depend inevitably on whether the
|
|
||||||
application developer has provided any hooks for you to hang your own
|
|
||||||
code on and, if there are such hooks, what they allow you to
|
|
||||||
do.@footnote{Of course, in the world of free software, you always have
|
|
||||||
the freedom to modify the application's source code to your own
|
|
||||||
requirements. Here we are concerned with the extension options that the
|
|
||||||
application has provided for without your needing to modify its source
|
|
||||||
code.} For example@dots{}
|
|
||||||
|
|
||||||
@itemize @bullet
|
|
||||||
@item
|
|
||||||
If the application permits you to load and execute any Guile code, the
|
|
||||||
world is your oyster. You can extend the application in any way that
|
|
||||||
you choose.
|
|
||||||
|
|
||||||
@item
|
|
||||||
A more cautious application might allow you to load and execute Guile
|
|
||||||
code, but only in a @dfn{safe} environment, where the interface
|
|
||||||
available is restricted by the application from the standard Guile API.
|
|
||||||
|
|
||||||
@item
|
|
||||||
Or a really fearful application might not provide a hook to really
|
|
||||||
execute user code at all, but just use Scheme syntax as a convenient way
|
|
||||||
for users to specify application data or configuration options.
|
|
||||||
@end itemize
|
|
||||||
|
|
||||||
In the last two cases, what you can do is, by definition, restricted by
|
|
||||||
the application, and you should refer to the application's own manual to
|
|
||||||
find out your options.
|
|
||||||
|
|
||||||
The most well known example of the first case is Emacs, with its
|
|
||||||
extension language Emacs Lisp: as well as being a text editor, Emacs
|
|
||||||
supports the loading and execution of arbitrary Emacs Lisp code. The
|
|
||||||
result of such openness has been dramatic: Emacs now benefits from
|
|
||||||
user-contributed Emacs Lisp libraries that extend the basic editing
|
|
||||||
function to do everything from reading news to psychoanalysis and
|
|
||||||
playing adventure games. The only limitation is that extensions are
|
|
||||||
restricted to the functionality provided by Emacs's built-in set of
|
|
||||||
primitive operations. For example, you can interact and display data by
|
|
||||||
manipulating the contents of an Emacs buffer, but you can't pop-up and
|
|
||||||
draw a window with a layout that is totally different to the Emacs
|
|
||||||
standard.
|
|
||||||
|
|
||||||
This situation with a Guile application that supports the loading of
|
|
||||||
arbitrary user code is similar, except perhaps even more so, because
|
|
||||||
Guile also supports the loading of extension libraries written in C.
|
|
||||||
This last point enables user code to add new primitive operations to
|
|
||||||
Guile, and so to bypass the limitation present in Emacs Lisp.
|
|
||||||
|
|
||||||
At this point, the distinction between an application developer and an
|
|
||||||
application user becomes rather blurred. Instead of seeing yourself as
|
|
||||||
a user extending an application, you could equally well say that you are
|
|
||||||
developing a new application of your own using some of the primitive
|
|
||||||
functionality provided by the original application. As such, all the
|
|
||||||
discussions of the preceding sections of this chapter are relevant to
|
|
||||||
how you can proceed with developing your extension.
|
|
Loading…
Add table
Add a link
Reference in a new issue