This is goops.info, produced by makeinfo version 4.3 from goops.texi.

INFO-DIR-SECTION The Algorithmic Language Scheme
START-INFO-DIR-ENTRY
* GOOPS: (goops).               The GOOPS reference manual.
END-INFO-DIR-ENTRY

This file documents GOOPS, an object oriented extension for Guile.

Copyright (C) 1999, 2000, 2001, 2003 Free Software Foundation

Permission is granted to make and distribute verbatim copies of this
manual provided the copyright notice and this permission notice are
preserved on all copies.


File: goops.info,  Node: Top,  Next: Introduction,  Prev: (dir),  Up: (dir)

* Menu:

* Introduction::
* Getting Started::
* Reference Manual::
* MOP Specification::

* Tutorial::

* Concept Index::
* Function and Variable Index::


File: goops.info,  Node: Introduction,  Next: Getting Started,  Prev: Top,  Up: Top

Introduction
************

GOOPS is the object oriented extension to Guile. Its implementation is
derived from STk-3.99.3 by Erick Gallesio and version 1.3 of Gregor
Kiczales `Tiny-Clos'.  It is very close in spirit to CLOS, the Common
Lisp Object System (`CLtL2') but is adapted for the Scheme language.
While GOOPS is not compatible with any of these systems, GOOPS contains
a compatibility module which allows for execution of STKlos programs.

Briefly stated, the GOOPS extension gives the user a full object
oriented system with multiple inheritance and generic functions with
multi-method dispatch.  Furthermore, the implementation relies on a true
meta object protocol, in the spirit of the one defined for CLOS
(`Gregor Kiczales: A Metaobject Protocol').


File: goops.info,  Node: Getting Started,  Next: Reference Manual,  Prev: Introduction,  Up: Top

Getting Started
***************

* Menu:

* Running GOOPS::

Examples of some basic GOOPS functionality.

* Methods::
* User-defined types::
* Asking for the type of an object::

See further in the GOOPS tutorial available in this distribution in
info (goops.info) and texinfo format.


File: goops.info,  Node: Running GOOPS,  Next: Methods,  Prev: Getting Started,  Up: Getting Started

Running GOOPS
-------------

  1. Type

          guile-oops

     You should now be at the Guile prompt ("guile> ").

  2. Type

          (use-modules (oop goops))

     to load GOOPS.  (If your system supports dynamic loading, you
     should be able to do this not only from `guile-oops' but from an
     arbitrary Guile interpreter.)

We're now ready to try some basic GOOPS functionality.


File: goops.info,  Node: Methods,  Next: User-defined types,  Prev: Running GOOPS,  Up: Getting Started

Methods
-------

     (define-method (+ (x <string>) (y <string>))
       (string-append x y))
     
     (+ 1 2) --> 3
     (+ "abc" "de") --> "abcde"


File: goops.info,  Node: User-defined types,  Next: Asking for the type of an object,  Prev: Methods,  Up: Getting Started

User-defined types
------------------

     (define-class <2D-vector> ()
       (x #:init-value 0 #:accessor x-component #:init-keyword #:x)
       (y #:init-value 0 #:accessor y-component #:init-keyword #:y))
     
     (use-modules (ice-9 format))
     
     (define-method (write (obj <2D-vector>) port)
       (display (format #f "<~S, ~S>" (x-component obj) (y-component obj))
                port))
     
     (define v (make <2D-vector> #:x 3 #:y 4))
     
     v --> <3, 4>
     
     (define-method (+ (x <2D-vector>) (y <2D-vector>))
       (make <2D-vector>
             #:x (+ (x-component x) (x-component y))
             #:y (+ (y-component x) (y-component y))))
     
     (+ v v) --> <6, 8>


File: goops.info,  Node: Asking for the type of an object,  Prev: User-defined types,  Up: Getting Started

Types
-----

     (class-of v) --> #<<class> <2D-vector> 40241ac0>
     <2D-vector>  --> #<<class> <2D-vector> 40241ac0>
     (class-of 1) --> #<<class> <integer> 401b2a98>
     <integer>    --> #<<class> <integer> 401b2a98>
     
     (is-a? v <2D-vector>) --> #t


File: goops.info,  Node: Reference Manual,  Next: MOP Specification,  Prev: Getting Started,  Up: Top

Reference Manual
****************

This chapter is the GOOPS reference manual.  It aims to describe all the
syntax, procedures, options and associated concepts that a typical
application author would need to understand in order to use GOOPS
effectively in their application.  It also describes what is meant by
the GOOPS "metaobject protocol" (aka "MOP"), and indicates how authors
can use the metaobject protocol to customize the behaviour of GOOPS
itself.

For a detailed specification of the GOOPS metaobject protocol, see
*Note MOP Specification::.

* Menu:

* Introductory Remarks::
* Defining New Classes::
* Creating Instances::
* Accessing Slots::
* Creating Generic Functions::
* Adding Methods to Generic Functions::
* Invoking Generic Functions::
* Redefining a Class::
* Changing the Class of an Instance::
* Introspection::
* Miscellaneous Functions::


File: goops.info,  Node: Introductory Remarks,  Next: Defining New Classes,  Up: Reference Manual

Introductory Remarks
====================

GOOPS is an object-oriented programming system based on a "metaobject
protocol" derived from the ones used in CLOS (the Common Lisp Object
System), tiny-clos (a small Scheme implementation of a subset of CLOS
functionality) and STKlos.

GOOPS can be used by application authors at a basic level without any
need to understand what the metaobject protocol (aka "MOP") is and how
it works.  On the other hand, the MOP underlies even the customizations
that application authors are likely to make use of very quickly -- such
as defining an `initialize' method to customize the initialization of
instances of an application-defined class -- and an understanding of
the MOP makes it much easier to explain such customizations in a precise
way.  And in the long run, understanding the MOP is the key both to
understanding GOOPS at a deeper level and to taking full advantage of
GOOPS' power, by customizing the behaviour of GOOPS itself.

Each of the following sections of the reference manual is arranged such
that the most basic usage is introduced first, and then subsequent
subsections discuss the related internal functions and metaobject
protocols, finishing with a description of how to customize that area of
functionality.

These introductory remarks continue with a few words about metaobjects
and the MOP.  Readers who do not want to be bothered yet with the MOP
and customization could safely skip this subsection on a first reading,
and should correspondingly skip subsequent subsections that are
concerned with internals and customization.

In general, this reference manual assumes familiarity with standard
object oriented concepts and terminology.  However, some of the terms
used in GOOPS are less well known, so the Terminology subsection
provides definitions for these terms.

* Menu:

* Metaobjects and the Metaobject Protocol::
* Terminology::


File: goops.info,  Node: Metaobjects and the Metaobject Protocol,  Next: Terminology,  Up: Introductory Remarks

Metaobjects and the Metaobject Protocol
---------------------------------------

The conceptual building blocks of GOOPS are classes, slot definitions,
instances, generic functions and methods.  A class is a grouping of
inheritance relations and slot definitions.  An instance is an object
with slots that are allocated following the rules implied by its class's
superclasses and slot definitions.  A generic function is a collection
of methods and rules for determining which of those methods to apply
when the generic function is invoked.  A method is a procedure and a set
of specializers that specify the type of arguments to which the
procedure is applicable.

Of these entities, GOOPS represents classes, generic functions and
methods as "metaobjects".  In other words, the values in a GOOPS
program that describe classes, generic functions and methods, are
themselves instances (or "objects") of special GOOPS classes that
encapsulate the behaviour, respectively, of classes, generic functions,
and methods.

(The other two entities are slot definitions and instances.  Slot
definitions are not strictly instances, but every slot definition is
associated with a GOOPS class that specifies the behaviour of the slot
as regards accessibility and protection from garbage collection.
Instances are of course objects in the usual sense, and there is no
benefit from thinking of them as metaobjects.)

The "metaobject protocol" (aka "MOP") is the specification of the
generic functions which determine the behaviour of these metaobjects and
the circumstances in which these generic functions are invoked.

For a concrete example of what this means, consider how GOOPS calculates
the set of slots for a class that is being defined using
`define-class'.  The desired set of slots is the union of the new
class's direct slots and the slots of all its superclasses.  But
`define-class' itself does not perform this calculation.  Instead,
there is a method of the `initialize' generic function that is
specialized for instances of type `<class>', and it is this method that
performs the slot calculation.

`initialize' is a generic function which GOOPS calls whenever a new
instance is created, immediately after allocating memory for a new
instance, in order to initialize the new instance's slots.  The sequence
of steps is as follows.

   * `define-class' uses `make' to make a new instance of the
     `<class>', passing as initialization arguments the superclasses,
     slot definitions and class options that were specified in the
     `define-class' form.

   * `make' allocates memory for the new instance, and then invokes the
     `initialize' generic function to initialize the new instance's
     slots.

   * The `initialize' generic function applies the method that is
     specialized for instances of type `<class>', and this method
     performs the slot calculation.

In other words, rather than being hardcoded in `define-class', the
behaviour of class definition is encapsulated by generic function
methods that are specialized for the class `<class>'.

It is possible to create a new class that inherits from `<class>',
which is called a "metaclass", and to write a new `initialize' method
that is specialized for instances of the new metaclass.  Then, if the
`define-class' form includes a `#:metaclass' class option whose value
is the new metaclass, the class that is defined by the `define-class'
form will be an instance of the new metaclass rather than of the
default `<class>', and will be defined in accordance with the new
`initialize' method.  Thus the default slot calculation, as well as any
other aspect of the new class's relationship with its superclasses, can
be modified or overridden.

In a similar way, the behaviour of generic functions can be modified or
overridden by creating a new class that inherits from the standard
generic function class `<generic>', writing appropriate methods that
are specialized to the new class, and creating new generic functions
that are instances of the new class.

The same is true for method metaobjects.  And the same basic mechanism
allows the application class author to write an `initialize' method
that is specialized to their application class, to initialize instances
of that class.

Such is the power of the MOP.  Note that `initialize' is just one of a
large number of generic functions that can be customized to modify the
behaviour of application objects and classes and of GOOPS itself.  Each
subsequent section of the reference manual covers a particular area of
GOOPS functionality, and describes the generic functions that are
relevant for customization of that area.

We conclude this subsection by emphasizing a point that may seem
obvious, but contrasts with the corresponding situation in some other
MOP implementations, such as CLOS.  The point is simply that an
identifier which represents a GOOPS class or generic function is a
variable with a first-class value, the value being an instance of class
`<class>' or `<generic>'.  (In CLOS, on the other hand, a class
identifier is a symbol that indexes the corresponding class metaobject
in a separate namespace for classes.)  This is, of course, simply an
extension of the tendency in Scheme to avoid the unnecessary use of, on
the one hand, syntactic forms that require unevaluated arguments and,
on the other, separate identifier namespaces (e.g. for class names),
but it is worth noting that GOOPS conforms fully to this Schemely
principle.


File: goops.info,  Node: Terminology,  Prev: Metaobjects and the Metaobject Protocol,  Up: Introductory Remarks

Terminology
-----------

It is assumed that the reader is already familiar with standard object
orientation concepts such as classes, objects/instances,
inheritance/subclassing, generic functions and methods, encapsulation
and polymorphism.

This section explains some of the less well known concepts and
terminology that GOOPS uses, which are assumed by the following sections
of the reference manual.

* Menu:

* Metaclass::
* Class Precedence List::
* Accessor::


File: goops.info,  Node: Metaclass,  Next: Class Precedence List,  Up: Terminology

Metaclass
.........

A "metaclass" is the class of an object which represents a GOOPS class.
Put more succinctly, a metaclass is a class's class.

Most GOOPS classes have the metaclass `<class>' and, by default, any
new class that is created using `define-class' has the metaclass
`<class>'.

But what does this really mean?  To find out, let's look in more detail
at what happens when a new class is created using `define-class':

     (define-class <my-class> (<object>) . slots)

GOOPS actually expands the `define-class' form to something like this

     (define <my-class> (class (<object>) . slots))

and thence to

     (define <my-class>
       (make <class> #:supers (list <object>) #:slots slots))

In other words, the value of `<my-class>' is in fact an instance of the
class `<class>' with slot values specifying the superclasses and slot
definitions for the class `<my-class>'.  (`#:supers' and `#:slots' are
initialization keywords for the `dsupers' and `dslots' slots of the
`<class>' class.)

In order to take advantage of the full power of the GOOPS metaobject
protocol (*note MOP Specification::), it is sometimes desirable to
create a new class with a metaclass other than the default `<class>'.
This is done by writing:

     (define-class <my-class2> (<object>)
        slot ...
        #:metaclass <my-metaclass>)

GOOPS expands this to something like:

     (define <my-class2>
       (make <my-metaclass> #:supers (list <object>) #:slots slots))

In this case, the value of `<my-class2>' is an instance of the more
specialized class `<my-metaclass>'.  Note that `<my-metaclass>' itself
must previously have been defined as a subclass of `<class>'.  For a
full discussion of when and how it is useful to define new metaclasses,
see *Note MOP Specification::.

Now let's make an instance of `<my-class2>':

     (define my-object (make <my-class2> ...))

All of the following statements are correct expressions of the
relationships between `my-object', `<my-class2>', `<my-metaclass>' and
`<class>'.

   * `my-object' is an instance of the class `<my-class2>'.

   * `<my-class2>' is an instance of the class `<my-metaclass>'.

   * `<my-metaclass>' is an instance of the class `<class>'.

   * The class of `my-object' is `<my-class2>'.

   * The metaclass of `my-object' is `<my-metaclass>'.

   * The class of `<my-class2>' is `<my-metaclass>'.

   * The metaclass of `<my-class2>' is `<class>'.

   * The class of `<my-metaclass>' is `<class>'.

   * The metaclass of `<my-metaclass>' is `<class>'.

   * `<my-class2>' is not a metaclass, since it is does not inherit from
     `<class>'.

   * `<my-metaclass>' is a metaclass, since it inherits from `<class>'.


File: goops.info,  Node: Class Precedence List,  Next: Accessor,  Prev: Metaclass,  Up: Terminology

Class Precedence List
.....................

The "class precedence list" of a class is the list of all direct and
indirect superclasses of that class, including the class itself.

In the absence of multiple inheritance, the class precedence list is
ordered straightforwardly, beginning with the class itself and ending
with `<top>'.

For example, given this inheritance hierarchy:

     (define-class <invertebrate> (<object>) ...)
     (define-class <echinoderm> (<invertebrate>) ...)
     (define-class <starfish> (<echinoderm>) ...)

the class precedence list of <starfish> would be

     (<starfish> <echinoderm> <invertebrate> <object> <top>)

With multiple inheritance, the algorithm is a little more complicated.
A full description is provided by the GOOPS Tutorial: see *Note Class
precedence list::.

"Class precedence list" is often abbreviated, in documentation and
Scheme variable names, to "cpl".


File: goops.info,  Node: Accessor,  Prev: Class Precedence List,  Up: Terminology

Accessor
........

An "accessor" is a generic function with both reference and setter
methods.

     (define-accessor perimeter)

Reference methods for an accessor are defined in the same way as generic
function methods.

     (define-method (perimeter (s <square>))
       (* 4 (side-length s)))

Setter methods for an accessor are defined by specifying "(setter
<accessor-name>)" as the first parameter of the `define-method' call.

     (define-method ((setter perimeter) (s <square>) (n <number>))
       (set! (side-length s) (/ n 4)))

Once an appropriate setter method has been defined in this way, it can
be invoked using the generalized `set!' syntax, as in:

     (set! (perimeter s1) 18.3)


File: goops.info,  Node: Defining New Classes,  Next: Creating Instances,  Prev: Introductory Remarks,  Up: Reference Manual

Defining New Classes
====================

[ *fixme* Somewhere in this manual there needs to be an introductory
discussion about GOOPS classes, generic functions and methods, covering

   * how classes encapsulate related items of data in "slots"

   * why it is that, unlike in C++ and Java, a class does not
     encapsulate the methods that act upon the class (at least not in
     the C++/Java sense)

   * how generic functions provide a more general solution that
     provides for dispatch on all argument types, and avoids
     idiosyncracies like C++'s friend classes

   * how encapsulation in the sense of data- and code-hiding, or of
     distinguishing interface from implementation, is treated in Guile
     as an orthogonal concept to object orientation, and is the
     responsibility of the module system.

Some of this is covered in the Tutorial chapter, in *Note Generic
functions and methods:: - perhaps the best solution would be to expand
the discussion there. ]

* Menu:

* Basic Class Definition::
* Class Options::
* Slot Options::
* Class Definition Internals::
* Customizing Class Definition::
* STKlos Compatibility::


File: goops.info,  Node: Basic Class Definition,  Next: Class Options,  Up: Defining New Classes

Basic Class Definition
----------------------

New classes are defined using the `define-class' syntax, with arguments
that specify the classes that the new class should inherit from, the
direct slots of the new class, and any required class options.

 - syntax: define-class name (super ...) slot-definition ... . options
     Define a class called NAME that inherits from SUPERs, with direct
     slots defined by SLOT-DEFINITIONs and class options OPTIONS.  The
     newly created class is bound to the variable name NAME in the
     current environment.

     Each SLOT-DEFINITION is either a symbol that names the slot or a
     list,

          (SLOT-NAME-SYMBOL . SLOT-OPTIONS)

     where SLOT-NAME-SYMBOL is a symbol and SLOT-OPTIONS is a list with
     an even number of elements.  The even-numbered elements of
     SLOT-OPTIONS (counting from zero) are slot option keywords; the
     odd-numbered elements are the corresponding values for those
     keywords.

     OPTIONS is a similarly structured list containing class option
     keywords and corresponding values.

The standard GOOPS class and slot options are described in the following
subsections: see *Note Class Options:: and *Note Slot Options::.

Example 1.  Define a class that combines two pre-existing classes by
inheritance but adds no new slots.

     (define-class <combined> (<tree> <bicycle>))

Example 2.  Define a `regular-polygon' class with slots for side length
and number of sides that have default values and can be accessed via
the generic functions `side-length' and `num-sides'.

     (define-class <regular-polygon> ()
       (sl #:init-value 1 #:accessor side-length)
       (ns #:init-value 5 #:accessor num-sides))

Example 3.  Define a class whose behavior (and that of its instances) is
customized via an application-defined metaclass.

     (define-class <tcpip-fsm> ()
       (s #:init-value #f #:accessor state)
       ...
       #:metaclass <finite-state-class>)


File: goops.info,  Node: Class Options,  Next: Slot Options,  Prev: Basic Class Definition,  Up: Defining New Classes

Class Options
-------------

 - class option: #:metaclass metaclass
     The `#:metaclass' class option specifies the metaclass of the class
     being defined.  METACLASS must be a class that inherits from
     `<class>'.  For an introduction to the use of metaclasses, see
     *Note Metaobjects and the Metaobject Protocol:: and *Note
     Metaclass::.

     If the `#:metaclass' option is absent, GOOPS reuses or constructs a
     metaclass for the new class by calling `ensure-metaclass' (*note
     ensure-metaclass: Class Definition Internals.).

 - class option: #:name name
     The `#:name' class option specifies the new class's name.  This
     name is used to identify the class whenever related objects - the
     class itself, its instances and its subclasses - are printed.

     If the `#:name' option is absent, GOOPS uses the first argument to
     `define-class' as the class name.

 - class option: #:environment environment
     *fixme* Not sure about this one, but I think that the
     `#:environment' option specifies the environment in which the
     class's getters and setters are computed and evaluated.

     If the `#:environment' option is not specified, the class's
     environment defaults to the top-level environment in which the
     `define-class' form appears.


File: goops.info,  Node: Slot Options,  Next: Class Definition Internals,  Prev: Class Options,  Up: Defining New Classes

Slot Options
------------

 - slot option: #:allocation allocation
     The `#:allocation' option tells GOOPS how to allocate storage for
     the slot.  Possible values for ALLOCATION are

        * `#:instance'

          Indicates that GOOPS should create separate storage for this
          slot in each new instance of the containing class (and its
          subclasses).

        * `#:class'

          Indicates that GOOPS should create storage for this slot that
          is shared by all instances of the containing class (and its
          subclasses).  In other words, a slot in class C with
          allocation `#:class' is shared by all INSTANCEs for which
          `(is-a? INSTANCE C)'.

        * `#:each-subclass'

          Indicates that GOOPS should create storage for this slot that
          is shared by all _direct_ instances of the containing class,
          and that whenever a subclass of the containing class is
          defined, GOOPS should create a new storage for the slot that
          is shared by all _direct_ instances of the subclass.  In
          other words, a slot with allocation `#:each-subclass' is
          shared by all instances with the same `class-of'.

        * `#:virtual'

          Indicates that GOOPS should not allocate storage for this
          slot.  The slot definition must also include the `#:slot-ref'
          and `#:slot-set!' options to specify how to reference and set
          the value for this slot.

     The default value is `#:instance'.

     Slot allocation options are processed when defining a new class by
     the generic function `compute-get-n-set', which is specialized by
     the class's metaclass.  Hence new types of slot allocation can be
     implemented by defining a new metaclass and a method for
     `compute-get-n-set' that is specialized for the new metaclass.  For
     an example of how to do this, see *Note Customizing Class
     Definition::.

 - slot option: #:slot-ref getter
 - slot option: #:slot-set! setter
     The `#:slot-ref' and `#:slot-set!' options must be specified if
     the slot allocation is `#:virtual', and are ignored otherwise.

     GETTER should be a closure taking a single INSTANCE parameter that
     returns the current slot value.  SETTER should be a closure taking
     two parameters - INSTANCE and NEW-VAL - that sets the slot value
     to NEW-VAL.

 - slot option: #:getter getter
 - slot option: #:setter setter
 - slot option: #:accessor accessor
     These options, if present, tell GOOPS to create generic function
     and method definitions that can be used to get and set the slot
     value more conveniently than by using `slot-ref' and `slot-set!'.

     GETTER specifies a generic function to which GOOPS will add a
     method for getting the slot value.  SETTER specifies a generic
     function to which GOOPS will add a method for setting the slot
     value.  ACCESSOR specifies an accessor to which GOOPS will add
     methods for both getting and setting the slot value.

     So if a class includes a slot definition like this:

          (c #:getter get-count #:setter set-count #:accessor count)

     GOOPS defines generic function methods such that the slot value
     can be referenced using either the getter or the accessor -

          (let ((current-count (get-count obj))) ...)
          (let ((current-count (count obj))) ...)

     - and set using either the setter or the accessor -

          (set-count obj (+ 1 current-count))
          (set! (count obj) (+ 1 current-count))

     Note that

        * with an accessor, the slot value is set using the generalized
          `set!' syntax

        * in practice, it is unusual for a slot to use all three of
          these options: read-only, write-only and read-write slots
          would typically use only `#:getter', `#:setter' and
          `#:accessor' options respectively.

     If the specified names are already bound in the top-level
     environment to values that cannot be upgraded to generic
     functions, those values are overwritten during evaluation of the
     `define-class' that contains the slot definition.  For details,
     see *Note ensure-generic: Generic Function Internals.

 - slot option: #:init-value init-value
 - slot option: #:init-form init-form
 - slot option: #:init-thunk init-thunk
 - slot option: #:init-keyword init-keyword
     These options provide various ways to specify how to initialize the
     slot's value at instance creation time.  INIT-VALUE is a fixed
     value.  INIT-THUNK is a procedure of no arguments that is called
     when a new instance is created and should return the desired
     initial slot value.  INIT-FORM is an unevaluated expression that
     gets evaluated when a new instance is created and should return
     the desired initial slot value.  INIT-KEYWORD is a keyword that
     can be used to pass an initial slot value to `make' when creating
     a new instance.

     If more than one of these options is specified for the same slot,
     the order of precedence, highest first is

        * `#:init-keyword', if INIT-KEYWORD is present in the options
          passed to `make'

        * `#:init-thunk', `#:init-form' or `#:init-value'.

     If the slot definition contains more than one initialization
     option of the same precedence, the later ones are ignored.  If a
     slot is not initialized at all, its value is unbound.

     In general, slots that are shared between more than one instance
     are only initialized at new instance creation time if the slot
     value is unbound at that time.  However, if the new instance
     creation specifies a valid init keyword and value for a shared
     slot, the slot is re-initialized regardless of its previous value.

     Note, however, that the power of GOOPS' metaobject protocol means
     that everything written here may be customized or overridden for
     particular classes!  The slot initializations described here are
     performed by the least specialized method of the generic function
     `initialize', whose signature is

          (define-method (initialize (object <object>) initargs) ...)

     The initialization of instances of any given class can be
     customized by defining a `initialize' method that is specialized
     for that class, and the author of the specialized method may
     decide to call `next-method' - which will result in a call to the
     next less specialized `initialize' method - at any point within the
     specialized code, or maybe not at all.  In general, therefore, the
     initialization mechanisms described here may be modified or
     overridden by more specialized code, or may not be supported at
     all for particular classes.


File: goops.info,  Node: Class Definition Internals,  Next: Customizing Class Definition,  Prev: Slot Options,  Up: Defining New Classes

Class Definition Internals
--------------------------

Implementation notes: `define-class' expands to an expression which

   * checks that it is being evaluated only at top level

   * defines any accessors that are implied by the SLOT-DEFINITIONs

   * uses `class' to create the new class (*note class: Class
     Definition Internals.)

   * checks for a previous class definition for NAME and, if found,
     handles the redefinition by invoking `class-redefinition' (*note
     Redefining a Class::).

 - syntax: class name (super ...) slot-definition ... . options
     Return a newly created class that inherits from SUPERs, with
     direct slots defined by SLOT-DEFINITIONs and class options
     OPTIONS.  For the format of SLOT-DEFINITIONs and OPTIONS, see
     *Note define-class: Basic Class Definition.

Implementation notes: `class' expands to an expression which

   * processes the class and slot definition options to check that they
     are well-formed, to convert the `#:init-form' option to an
     `#:init-thunk' option, to supply a default environment parameter
     (the current top-level environment) and to evaluate all the bits
     that need to be evaluated

   * calls `make-class' to create the class with the processed and
     evaluated parameters.

 - procedure: make-class supers slots . options
     Return a newly created class that inherits from SUPERS, with
     direct slots defined by SLOTS and class options OPTIONS.  For the
     format of SLOTS and OPTIONS, see *Note define-class: Basic Class
     Definition, except note that for `make-class', SLOTS and OPTIONS
     are separate list parameters: SLOTS here is a list of slot
     definitions.

Implementation notes: `make-class'

   * adds `<object>' to the SUPERS list if SUPERS is empty or if none
     of the classes in SUPERS have `<object>' in their class precedence
     list

   * defaults the `#:environment', `#:name' and `#:metaclass' options,
     if they are not specified by OPTIONS, to the current top-level
     environment, the unbound value, and `(ensure-metaclass SUPERS)'
     respectively (*note ensure-metaclass: Class Definition Internals.)

   * checks for duplicate classes in SUPERS and duplicate slot names in
     SLOTS, and signals an error if there are any duplicates

   * calls `make', passing the metaclass as the first parameter and all
     other parameters as option keywords with values.

 - procedure: ensure-metaclass supers env
     Return a metaclass suitable for a class that inherits from the
     list of classes in SUPERS.  The returned metaclass is the union by
     inheritance of the metaclasses of the classes in SUPERS.

     In the simplest case, where all the SUPERS are straightforward
     classes with metaclass `<class>', the returned metaclass is just
     `<class>'.

     For a more complex example, suppose that SUPERS contained one
     class with metaclass `<operator-class>' and one with metaclass
     `<foreign-object-class>'.  Then the returned metaclass would be a
     class that inherits from both `<operator-class>' and
     `<foreign-object-class>'.

     If SUPERS is the empty list, `ensure-metaclass' returns the
     default GOOPS metaclass `<class>'.

     GOOPS keeps a list of the metaclasses created by
     `ensure-metaclass', so that each required type of metaclass only
     has to be created once.

     The `env' parameter is ignored.

 - procedure: ensure-metaclass-with-supers meta-supers
     `ensure-metaclass-with-supers' is an internal procedure used by
     `ensure-metaclass' (*note ensure-metaclass: Class Definition
     Internals.).  It returns a metaclass that is the union by
     inheritance of the metaclasses in META-SUPERS.

The internals of `make', which is ultimately used to create the new
class object, are described in *Note Customizing Instance Creation::,
which covers the creation and initialization of instances in general.


File: goops.info,  Node: Customizing Class Definition,  Next: STKlos Compatibility,  Prev: Class Definition Internals,  Up: Defining New Classes

Customizing Class Definition
----------------------------

During the initialization of a new class, GOOPS calls a number of
generic functions with the newly allocated class instance as the first
argument.  Specifically, GOOPS calls the generic function

   * (initialize CLASS ...)

where CLASS is the newly allocated class instance, and the default
`initialize' method for arguments of type `<class>' calls the generic
functions

   * (compute-cpl CLASS)

   * (compute-slots CLASS)

   * (compute-get-n-set CLASS SLOT-DEF), for each of the slot
     definitions returned by `compute-slots'

   * (compute-getter-method CLASS SLOT-DEF), for each of the slot
     definitions returned by `compute-slots' that includes a `#:getter'
     or `#:accessor' slot option

   * (compute-setter-method CLASS SLOT-DEF), for each of the slot
     definitions returned by `compute-slots' that includes a `#:setter'
     or `#:accessor' slot option.

If the metaclass of the new class is something more specialized than the
default `<class>', then the type of CLASS in the calls above is more
specialized than `<class>', and hence it becomes possible to define
generic function methods, specialized for the new class's metaclass,
that can modify or override the default behaviour of `initialize',
`compute-cpl' or `compute-get-n-set'.

`compute-cpl' computes the class precedence list ("CPL") for the new
class (*note Class precedence list::), and returns it as a list of
class objects.  The CPL is important because it defines a superclass
ordering that is used, when a generic function is invoked upon an
instance of the class, to decide which of the available generic function
methods is the most specific.  Hence `compute-cpl' could be customized
in order to modify the CPL ordering algorithm for all classes with a
special metaclass.

The default CPL algorithm is encapsulated by the `compute-std-cpl'
procedure, which is in turn called by the default `compute-cpl' method.

 - procedure: compute-std-cpl class
     Compute and return the class precedence list for CLASS according
     to the algorithm described in *Note Class precedence list::.

`compute-slots' computes and returns a list of all slot definitions for
the new class.  By default, this list includes the direct slot
definitions from the `define-class' form, plus the slot definitions
that are inherited from the new class's superclasses.  The default
`compute-slots' method uses the CPL computed by `compute-cpl' to
calculate this union of slot definitions, with the rule that slots
inherited from superclasses are shadowed by direct slots with the same
name.  One possible reason for customizing `compute-slots' would be to
implement an alternative resolution strategy for slot name conflicts.

`compute-get-n-set' computes the low-level closures that will be used
to get and set the value of a particular slot, and returns them in a
list with two elements.

The closures returned depend on how storage for that slot is allocated.
The standard `compute-get-n-set' method, specialized for classes of
type `<class>', handles the standard GOOPS values for the
`#:allocation' slot option (*note allocation: Slot Options.).  By
defining a new `compute-get-n-set' method for a more specialized
metaclass, it is possible to support new types of slot allocation.

Suppose you wanted to create a large number of instances of some class
with a slot that should be shared between some but not all instances of
that class - say every 10 instances should share the same slot storage.
The following example shows how to implement and use a new type of slot
allocation to do this.

     (define-class <batched-allocation-metaclass> (<class>))
     
     (let ((batch-allocation-count 0)
           (batch-get-n-set #f))
       (define-method (compute-get-n-set (class <batched-allocation-metaclass>) s)
         (case (slot-definition-allocation s)
           ((#:batched)
            ;; If we've already used the same slot storage for 10 instances,
            ;; reset variables.
            (if (= batch-allocation-count 10)
                (begin
                  (set! batch-allocation-count 0)
                  (set! batch-get-n-set #f)))
            ;; If we don't have a current pair of get and set closures,
            ;; create one.  make-closure-variable returns a pair of closures
            ;; around a single Scheme variable - see goops.scm for details.
            (or batch-get-n-set
                (set! batch-get-n-set (make-closure-variable)))
            ;; Increment the batch allocation count.
            (set! batch-allocation-count (+ batch-allocation-count 1))
            batch-get-n-set)
     
           ;; Call next-method to handle standard allocation types.
           (else (next-method)))))
     
     (define-class <class-using-batched-slot> ()
       ...
       (c #:allocation #:batched)
       ...
       #:metaclass <batched-allocation-metaclass>)

The usage of `compute-getter-method' and `compute-setter-method' is
described in *Note MOP Specification::.

`compute-cpl' and `compute-get-n-set' are called by the standard
`initialize' method for classes whose metaclass is `<class>'.  But
`initialize' itself can also be modified, by defining an `initialize'
method specialized to the new class's metaclass.  Such a method could
complete override the standard behaviour, by not calling
`(next-method)' at all, but more typically it would perform additional
class initialization steps before and/or after calling `(next-method)'
for the standard behaviour.


File: goops.info,  Node: STKlos Compatibility,  Prev: Customizing Class Definition,  Up: Defining New Classes

STKlos Compatibility
--------------------

If the STKlos compatibility module is loaded, `define-class' is
overwritten by a STKlos-specific definition; the standard GOOPS
definition of `define-class' remains available in
`standard-define-class'.

 - syntax: standard-define-class name (super ...) slot-definition ... .
          options
     `standard-define-class' is equivalent to the standard GOOPS
     `define-class'.


File: goops.info,  Node: Creating Instances,  Next: Accessing Slots,  Prev: Defining New Classes,  Up: Reference Manual

Creating Instances
==================

* Menu:

* Basic Instance Creation::
* Customizing Instance Creation::


File: goops.info,  Node: Basic Instance Creation,  Next: Customizing Instance Creation,  Up: Creating Instances

Basic Instance Creation
-----------------------

To create a new instance of any GOOPS class, use the generic function
`make' or `make-instance', passing the required class and any
appropriate instance initialization arguments as keyword and value
pairs.  Note that `make' and `make-instances' are aliases for each
other - their behaviour is identical.

 - generic: make
 - method: make (class <class>) . initargs
     Create and return a new instance of class CLASS, initialized using
     INITARGS.

     In theory, INITARGS can have any structure that is understood by
     whatever methods get applied when the `initialize' generic function
     is applied to the newly allocated instance.

     In practice, specialized `initialize' methods would normally call
     `(next-method)', and so eventually the standard GOOPS `initialize'
     methods are applied.  These methods expect INITARGS to be a list
     with an even number of elements, where even-numbered elements
     (counting from zero) are keywords and odd-numbered elements are
     the corresponding values.

     GOOPS processes initialization argument keywords automatically for
     slots whose definition includes the `#:init-keyword' option (*note
     init-keyword: Slot Options.).  Other keyword value pairs can only
     be processed by an `initialize' method that is specialized for the
     new instance's class.  Any unprocessed keyword value pairs are
     ignored.

 - generic: make-instance
 - method: make-instance (class <class>) . initargs
     `make-instance' is an alias for `make'.


File: goops.info,  Node: Customizing Instance Creation,  Prev: Basic Instance Creation,  Up: Creating Instances

Customizing Instance Creation
-----------------------------

`make' itself is a generic function.  Hence the `make' invocation
itself can be customized in the case where the new instance's metaclass
is more specialized than the default `<class>', by defining a `make'
method that is specialized to that metaclass.

Normally, however, the method for classes with metaclass `<class>' will
be applied.  This method calls two generic functions:

   * (allocate-instance CLASS . INITARGS)

   * (initialize INSTANCE . INITARGS)

`allocate-instance' allocates storage for and returns the new instance,
uninitialized.  You might customize `allocate-instance', for example,
if you wanted to provide a GOOPS wrapper around some other object
programming system.

To do this, you would create a specialized metaclass, which would act as
the metaclass for all classes and instances from the other system.  Then
define an `allocate-instance' method, specialized to that metaclass,
which calls a Guile primitive C function, which in turn allocates the
new instance using the interface of the other object system.

In this case, for a complete system, you would also need to customize a
number of other generic functions like `make' and `initialize', so that
GOOPS knows how to make classes from the other system, access instance
slots, and so on.

`initialize' initializes the instance that is returned by
`allocate-instance'.  The standard GOOPS methods perform
initializations appropriate to the instance class.

   * At the least specialized level, the method for instances of type
     `<object>' performs internal GOOPS instance initialization, and
     initializes the instance's slots according to the slot definitions
     and any slot initialization keywords that appear in INITARGS.

   * The method for instances of type `<class>' calls `(next-method)',
     then performs the class initializations described in *Note
     Customizing Class Definition::.

   * and so on for generic functions, method, operator classes ...

Similarly, you can customize the initialization of instances of any
application-defined class by defining an `initialize' method
specialized to that class.

Imagine a class whose instances' slots need to be initialized at
instance creation time by querying a database.  Although it might be
possible to achieve this a combination of `#:init-thunk' keywords and
closures in the slot definitions, it is neater to write an `initialize'
method for the class that queries the database once and initializes all
the dependent slot values according to the results.


File: goops.info,  Node: Accessing Slots,  Next: Creating Generic Functions,  Prev: Creating Instances,  Up: Reference Manual

Accessing Slots
===============

The definition of a slot contains at the very least a slot name, and may
also contain various slot options, including getter, setter and/or
accessor functions for the slot.

It is always possible to access slots by name, using the various
"slot-ref" and "slot-set!" procedures described in the following
subsections.  For example,

     (define-class <my-class> ()      ;; Define a class with slots
       (count #:init-value 0)         ;; named "count" and "cache".
       (cache #:init-value '())
       ...)
     
     (define inst (make <my-class>))  ;; Make an instance of this class.
     
     (slot-set! inst 'count 5)        ;; Set the value of the "count"
                                      ;; slot to 5.
     
     (slot-set! inst 'cache           ;; Modify the value of the
       (cons (cons "^it" "It")        ;; "cache" slot.
             (slot-ref inst 'cache)))

If a slot definition includes a getter, setter or accessor function,
these can be used instead of `slot-ref' and `slot-set!' to access the
slot.

     (define-class <adv-class> ()     ;; Define a new class whose slots
       (count #:setter set-count)     ;; use a getter, a setter and
       (cache #:accessor cache)       ;; an accessor.
       (csize #:getter cache-size)
       ...)
     
     (define inst (make <adv-class>)) ;; Make an instance of this class.
     
     (set-count inst 5)               ;; Set the value of the "count"
                                      ;; slot to 5.
     
     (set! (cache inst)               ;; Modify the value of the
       (cons (cons "^it" "It")        ;; "cache" slot.
             (cache inst)))
     
     (let ((size (cache-size inst)))  ;; Get the value of the "csize"
       ...)                           ;; slot.

Whichever of these methods is used to access slots, GOOPS always calls
the low-level "getter" and "setter" closures for the slot to get and
set its value.  These closures make sure that the slot behaves
according to the `#:allocation' type that was specified in the slot
definition (*note allocation: Slot Options.).  (For more about these
closures, see *Note compute-get-n-set: Customizing Class Definition.)

* Menu:

* Instance Slots::
* Class Slots::
* Handling Slot Access Errors::


File: goops.info,  Node: Instance Slots,  Next: Class Slots,  Up: Accessing Slots

Instance Slots
--------------

Any slot, regardless of its allocation, can be queried, referenced and
set using the following four primitive procedures.

 - primitive procedure: slot-exists? obj slot-name
     Return `#t' if OBJ has a slot with name SLOT-NAME, otherwise `#f'.

 - primitive procedure: slot-bound? obj slot-name
     Return `#t' if the slot named SLOT-NAME in OBJ has a value,
     otherwise `#f'.

     `slot-bound?' calls the generic function `slot-missing' if OBJ
     does not have a slot called SLOT-NAME (*note slot-missing:
     Handling Slot Access Errors.).

 - primitive procedure: slot-ref obj slot-name
     Return the value of the slot named SLOT-NAME in OBJ.

     `slot-ref' calls the generic function `slot-missing' if OBJ does
     not have a slot called SLOT-NAME (*note slot-missing: Handling
     Slot Access Errors.).

     `slot-ref' calls the generic function `slot-unbound' if the named
     slot in OBJ does not have a value (*note slot-unbound: Handling
     Slot Access Errors.).

 - primitive procedure: slot-set! obj slot-name value
     Set the value of the slot named SLOT-NAME in OBJ to VALUE.

     `slot-set!' calls the generic function `slot-missing' if OBJ does
     not have a slot called SLOT-NAME (*note slot-missing: Handling
     Slot Access Errors.).

GOOPS stores information about slots in class metaobjects.  Internally,
all of these procedures work by looking up the slot definition for the
slot named SLOT-NAME in the class metaobject for `(class-of OBJ)', and
then using the slot definition's "getter" and "setter" closures to get
and set the slot value.

The next four procedures differ from the previous ones in that they take
the class metaobject as an explicit argument, rather than assuming
`(class-of OBJ)'.  Therefore they allow you to apply the "getter" and
"setter" closures of a slot definition in one class to an instance of a
different class.

[ *fixme* I have no idea why this is useful!  Perhaps when a slot in
`(class-of OBJ)' shadows a slot with the same name in one of its
superclasses?  There should be an enlightening example here. ]

 - primitive procedure: slot-exists-using-class? class obj slot-name
     Return `#t' if the class metaobject CLASS has a slot definition
     for a slot with name SLOT-NAME, otherwise `#f'.

 - primitive procedure: slot-bound-using-class? class obj slot-name
     Return `#t' if applying `slot-ref-using-class' to the same
     arguments would call the generic function `slot-unbound', otherwise
     `#f'.

     `slot-bound-using-class?' calls the generic function
     `slot-missing' if CLASS does not have a slot definition for a slot
     called SLOT-NAME (*note slot-missing: Handling Slot Access
     Errors.).

 - primitive procedure: slot-ref-using-class class obj slot-name
     Apply the "getter" closure for the slot named SLOT-NAME in CLASS
     to OBJ, and return its result.

     `slot-ref-using-class' calls the generic function `slot-missing'
     if CLASS does not have a slot definition for a slot called
     SLOT-NAME (*note slot-missing: Handling Slot Access Errors.).

     `slot-ref-using-class' calls the generic function `slot-unbound'
     if the application of the "getter" closure to OBJ returns an
     unbound value (*note slot-unbound: Handling Slot Access Errors.).

 - primitive procedure: slot-set-using-class! class obj slot-name value
     Apply the "setter" closure for the slot named SLOT-NAME in CLASS
     to OBJ and VALUE.

     `slot-set-using-class!' calls the generic function `slot-missing'
     if CLASS does not have a slot definition for a slot called
     SLOT-NAME (*note slot-missing: Handling Slot Access Errors.).

