From f60a835300834b0e2d8d5f272e1180231806b71b Mon Sep 17 00:00:00 2001 From: Neil Jerram Date: Mon, 6 Dec 2010 22:28:39 +0000 Subject: [PATCH] Merge `tutorial' and `reference' treatments of the same basic GOOPS material * doc/ref/goops.texi (GOOPS): Move use of (oop goops) here. (Class Definition): Merged with `Defining New Classes' (Instance Creation): Insert before covering slot options. Merge in material from `Creating Instances'. (Slot Options): Merged some better wording and index entries from the tutorial version. (Slot Description Example): New node, containing the material from the tutorial. (Methods and Generic Functions, Inheritance): Tutorial sections moved into main line of the manual. * doc/ref/goops-tutorial.texi: Nothing left here now. --- doc/ref/goops-tutorial.texi | 798 ------------------------------- doc/ref/goops.texi | 901 +++++++++++++++++++++++++++++------- 2 files changed, 729 insertions(+), 970 deletions(-) diff --git a/doc/ref/goops-tutorial.texi b/doc/ref/goops-tutorial.texi index 52b293122..d2cf6404a 100644 --- a/doc/ref/goops-tutorial.texi +++ b/doc/ref/goops-tutorial.texi @@ -29,801 +29,3 @@ @c @macro guile @c was {\stk} @c Guile @c @end macro - -To start using @goops{} you first need to import the @code{(oop goops)} -module. You can do this at the Guile REPL by evaluating: - -@lisp -(use-modules (oop goops)) -@end lisp -@findex (oop goops) - -@menu -* Class definition:: -* Instance creation and slot access:: -* Slot description:: -* Inheritance:: -* Generic functions:: -@end menu - -@node Class definition -@subsection Class definition - -A new class is defined with the @code{define-class} syntax: - -@findex define-class -@cindex class -@lisp -(define-class @var{class} (@var{superclass} @dots{}) - @var{slot-description} @dots{} - @var{class-option} @dots{}) -@end lisp - -@var{class} is the class being defined. The list of @var{superclass}es -specifies which existing classes, if any, to inherit slots and -properties from. @dfn{Slots} hold per-instance@footnote{Usually --- but -see also the @code{#:allocation} slot option.} data, for instances of -that class --- like ``fields'' or ``member variables'' in other object -oriented systems. Each @var{slot-description} gives the name of a slot -and optionally some ``properties'' of this slot; for example its initial -value, the name of a function which will access its value, and so on. -Slot descriptions and inheritance are discussed more below. For class -options, see @ref{Class Options}. -@cindex slot - -As an example, let us define a type for representing a complex number -in terms of two real numbers.@footnote{Of course Guile already -provides complex numbers, and @code{} is in fact a predefined -class in GOOPS; but the definition here is still useful as an -example.} This can be done with the following class definition: - -@lisp -(define-class () - r i) -@end lisp - -This binds the variable @code{} to a new class whose -instances will contain two slots. These slots are called @code{r} and -@code{i} and will hold the real and imaginary parts of a complex -number. Note that this class inherits from @code{}, which is a -predefined class.@footnote{@code{} is the direct superclass of -the predefined class @code{}; @code{} is the -superclass of @code{}, and @code{} is the superclass of -@code{}.} - -@node Instance creation and slot access -@subsection Instance creation and slot access - -Creation of an instance of a previously defined class can be done with -@code{make}. This procedure takes one mandatory parameter which is the -class of the instance which must be created, and a list of optional -arguments. Optional arguments are generally used to initialize some of -the slots of the newly created instance. For instance, the following -form - -@findex make -@cindex instance -@lisp -(define c (make )) -@end lisp - -@noindent -will create a new @code{} object and will bind it to the @code{c} -Scheme variable. - -Accessing the slots of the new complex number can be done with the -@code{slot-ref} and the @code{slot-set!} primitives. @code{slot-set!} -sets the value of an object slot and @code{slot-ref} retrieves it. - -@findex slot-set! -@findex slot-ref -@lisp -@group -(slot-set! c 'r 10) -(slot-set! c 'i 3) -(slot-ref c 'r) @result{} 10 -(slot-ref c 'i) @result{} 3 -@end group -@end lisp - -Using the @code{describe} function is a simple way to see all the -slots of an object at one time: this function prints all the slots of an -object on the standard output. - -First load the module @code{(oop goops describe)}: - -@example -@code{(use-modules (oop goops describe))} -@end example - -@noindent -Then the expression - -@lisp -(describe c) -@end lisp - -@noindent -will print the following information on the standard output: - -@smalllisp -#< 401d8638> is an instance of class -Slots are: - r = 10 - i = 3 -@end smalllisp - -@node Slot description -@subsection Slot description -@c \label{slot-description} - -When specifying a slot (in a @code{(define-class @dots{})} form), -various options can be specified in addition to the slot's name. Each -option is specified by a keyword. The list of authorized keywords is -given below: - -@cindex keyword -@itemize @bullet -@item -@code{#:init-value} permits to supply a constant default value for the -slot. The value is obtained by evaluating the form given after the -@code{#:init-value} at class definition time. -@cindex default slot value -@findex #:init-value - -@item -@code{#:init-form} specifies a form that, when evaluated, will return -an initial value for the slot. The form is evaluated each time that -an instance of the class is created, in the lexical environment of the -containing @code{define-class} expression. -@cindex default slot value -@findex #:init-form - -@item -@code{#:init-thunk} permits to supply a thunk that will provide a -default value for the slot. The value is obtained by invoking the -thunk at instance creation time. -@findex default slot value -@findex #:init-thunk - -@item -@code{#:init-keyword} permits to specify a keyword for initializing the -slot. The init-keyword may be provided during instance creation (i.e. in -the @code{make} optional parameter list). Specifying such a keyword -during instance initialization will supersede the default slot -initialization possibly given with @code{#:init-form}. -@findex #:init-keyword - -@item -@code{#:getter} permits to supply the name for the -slot getter. The name binding is done in the -environment of the @code{define-class} macro. -@findex #:getter -@cindex top level environment -@cindex getter - -@item -@code{#:setter} permits to supply the name for the -slot setter. The name binding is done in the -environment of the @code{define-class} macro. -@findex #:setter -@cindex top level environment -@cindex setter - -@item -@code{#:accessor} permits to supply the name for the -slot accessor. The name binding is done in the global -environment. An accessor permits to get and -set the value of a slot. Setting the value of a slot is done with the extended -version of @code{set!}. -@findex set! -@findex #:accessor -@cindex top level environment -@cindex accessor - -@item -@code{#:allocation} permits to specify how storage for -the slot is allocated. Three kinds of allocation are provided. -They are described below: - -@itemize @minus -@item -@code{#:instance} indicates that each instance gets its own storage for -the slot. This is the default. -@item -@code{#:class} indicates that there is one storage location used by all -the direct and indirect instances of the class. This permits to define a -kind of global variable which can be accessed only by (in)direct -instances of the class which defines this slot. -@item -@code{#:each-subclass} indicates that there is one storage location used -by all the direct instances of the class. In other words, if two classes -are not siblings in the class hierarchy, they will not see the same -value. -@item -@code{#:virtual} indicates that no storage will be allocated for this -slot. It is up to the user to define a getter and a setter function for -this slot. Those functions must be defined with the @code{#:slot-ref} -and @code{#:slot-set!} options. See the example below. -@findex #:slot-set! -@findex #:slot-ref -@findex #:virtual -@findex #:class -@findex #:each-subclass -@findex #:instance -@findex #:allocation -@end itemize -@end itemize - -To illustrate slot description, we shall redefine the @code{} class -seen before. A definition could be: - -@lisp -(define-class () - (r #:init-value 0 #:getter get-r #:setter set-r! #:init-keyword #:r) - (i #:init-value 0 #:getter get-i #:setter set-i! #:init-keyword #:i)) -@end lisp - -With this definition, the @code{r} and @code{i} slot are set to 0 by -default. Value of a slot can also be specified by calling @code{make} -with the @code{#:r} and @code{#:i} keywords. Furthermore, the generic -functions @code{get-r} and @code{set-r!} (resp. @code{get-i} and -@code{set-i!}) are automatically defined by the system to read and write -the @code{r} (resp. @code{i}) slot. - -@lisp -(define c1 (make #:r 1 #:i 2)) -(get-r c1) @result{} 1 -(set-r! c1 12) -(get-r c1) @result{} 12 -(define c2 (make #:r 2)) -(get-r c2) @result{} 2 -(get-i c2) @result{} 0 -@end lisp - -Accessors provide an uniform access for reading and writing an object -slot. Writing a slot is done with an extended form of @code{set!} -which is close to the Common Lisp @code{setf} macro. So, another -definition of the previous @code{} class, using the -@code{#:accessor} option, could be: - -@findex set! -@lisp -(define-class () - (r #:init-value 0 #:accessor real-part #:init-keyword #:r) - (i #:init-value 0 #:accessor imag-part #:init-keyword #:i)) -@end lisp - -Using this class definition, reading the real part of the @code{c} -complex can be done with: -@lisp -(real-part c) -@end lisp -and setting it to the value contained in the @code{new-value} variable -can be done using the extended form of @code{set!}. -@lisp -(set! (real-part c) new-value) -@end lisp - -Suppose now that we have to manipulate complex numbers with rectangular -coordinates as well as with polar coordinates. One solution could be to -have a definition of complex numbers which uses one particular -representation and some conversion functions to pass from one -representation to the other. A better solution uses virtual slots. A -complete definition of the @code{} class using virtual slots is -given in Figure@ 2. - -@example -@group -@lisp -(define-class () - ;; True slots use rectangular coordinates - (r #:init-value 0 #:accessor real-part #:init-keyword #:r) - (i #:init-value 0 #:accessor imag-part #:init-keyword #:i) - ;; Virtual slots access do the conversion - (m #:accessor magnitude #:init-keyword #:magn - #:allocation #:virtual - #:slot-ref (lambda (o) - (let ((r (slot-ref o 'r)) (i (slot-ref o 'i))) - (sqrt (+ (* r r) (* i i))))) - #:slot-set! (lambda (o m) - (let ((a (slot-ref o 'a))) - (slot-set! o 'r (* m (cos a))) - (slot-set! o 'i (* m (sin a)))))) - (a #:accessor angle #:init-keyword #:angle - #:allocation #:virtual - #:slot-ref (lambda (o) - (atan (slot-ref o 'i) (slot-ref o 'r))) - #:slot-set! (lambda(o a) - (let ((m (slot-ref o 'm))) - (slot-set! o 'r (* m (cos a))) - (slot-set! o 'i (* m (sin a))))))) - -@end lisp -@center @emph{Fig 2: A @code{} number class definition using virtual slots} -@end group -@end example - -@sp 3 -This class definition implements two real slots (@code{r} and -@code{i}). Values of the @code{m} and @code{a} virtual slots are -calculated from real slot values. Reading a virtual slot leads to the -application of the function defined in the @code{#:slot-ref} -option. Writing such a slot leads to the application of the function -defined in the @code{#:slot-set!} option. For instance, the following -expression - -@findex #:slot-set! -@findex #:slot-ref -@lisp -(slot-set! c 'a 3) -@end lisp - -permits to set the angle of the @code{c} complex number. This expression -conducts, in fact, to the evaluation of the following expression - -@lisp -((lambda o m) - (let ((m (slot-ref o 'm))) - (slot-set! o 'r (* m (cos a))) - (slot-set! o 'i (* m (sin a)))) - c 3) -@end lisp - -A more complete example is given below: - -@example -@group -@smalllisp -(define c (make #:r 12 #:i 20)) -(real-part c) @result{} 12 -(angle c) @result{} 1.03037682652431 -(slot-set! c 'i 10) -(set! (real-part c) 1) -(describe c) -@print{} -#< 401e9b58> is an instance of class -Slots are: - r = 1 - i = 10 - m = 10.0498756211209 - a = 1.47112767430373 -@end smalllisp -@end group -@end example - -Since initialization keywords have been defined for the four slots, we -can now define the @code{make-rectangular} and @code{make-polar} standard -Scheme primitives. - -@lisp -(define make-rectangular - (lambda (x y) (make #:r x #:i y))) - -(define make-polar - (lambda (x y) (make #:magn x #:angle y))) -@end lisp - -@node Inheritance -@subsection Inheritance -@c \label{inheritance} - -@menu -* Class hierarchy and inheritance of slots:: -* Class precedence list:: -@end menu - -@node Class hierarchy and inheritance of slots -@subsubsection Class hierarchy and inheritance of slots -Inheritance is specified upon class definition. As said in the -introduction, @goops{} supports multiple inheritance. Here are some -class definitions: - -@lisp -(define-class A () a) -(define-class B () b) -(define-class C () c) -(define-class D (A B) d a) -(define-class E (A C) e c) -(define-class F (D E) f) -@end lisp - -@code{A}, @code{B}, @code{C} have a null list of super classes. In this -case, the system will replace it by the list which only contains -@code{}, the root of all the classes defined by -@code{define-class}. @code{D}, @code{E}, @code{F} use multiple -inheritance: each class inherits from two previously defined classes. -Those class definitions define a hierarchy which is shown in Figure@ 1. -In this figure, the class @code{} is also shown; this class is the -super class of all Scheme objects. In particular, @code{} is the -super class of all standard Scheme types. - -@example -@group -@iftex -@center @image{hierarchy,5in} -@end iftex -@ifnottex -@verbatiminclude hierarchy.txt -@end ifnottex - -@emph{Fig 1: A class hierarchy} -@emph{(@code{} which is the direct subclass of @code{} -and the direct superclass of @code{} has been omitted in this -figure.)} -@end group -@end example - -The set of slots of a given class is calculated by taking the union of the -slots of all its super class. For instance, each instance of the class -D, defined before will have three slots (@code{a}, @code{b} and -@code{d}). The slots of a class can be obtained by the @code{class-slots} -primitive. For instance, - -@lisp -(class-slots A) @result{} ((a)) -(class-slots E) @result{} ((a) (e) (c)) -(class-slots F) @result{} ((e) (c) (b) (d) (a) (f)) -@c used to be ((d) (a) (b) (c) (f)) -@end lisp - -@emph{Note: } The order of slots is not significant. - -@node Class precedence list -@subsubsection Class precedence list - -A class may have more than one superclass. @footnote{This section is an -adaptation of Jeff Dalton's (J.Dalton@@ed.ac.uk) @cite{Brief -introduction to CLOS}} With single inheritance (one superclass), it is -easy to order the super classes from most to least specific. This is the -rule: - -@display -@cartouche -Rule 1: Each class is more specific than its superclasses.@c was \bf -@end cartouche -@end display - -With multiple inheritance, ordering is harder. Suppose we have - -@lisp -(define-class X () - (x #:init-value 1)) - -(define-class Y () - (x #:init-value 2)) - -(define-class Z (X Y) - (@dots{})) -@end lisp - -In this case, the @code{Z} class is more specific than the @code{X} or -@code{Y} class for instances of @code{Z}. However, the @code{#:init-value} -specified in @code{X} and @code{Y} leads to a problem: which one -overrides the other? The rule in @goops{}, as in CLOS, is that the -superclasses listed earlier are more specific than those listed later. -So: - -@display -@cartouche -Rule 2: For a given class, superclasses listed earlier are more - specific than those listed later. -@end cartouche -@end display - -These rules are used to compute a linear order for a class and all its -superclasses, from most specific to least specific. This order is -called the ``class precedence list'' of the class. Given these two -rules, we can claim that the initial form for the @code{x} slot of -previous example is 1 since the class @code{X} is placed before @code{Y} -in class precedence list of @code{Z}. - -These two rules are not always enough to determine a unique order, -however, but they give an idea of how things work. Taking the @code{F} -class shown in Figure@ 1, the class precedence list is - -@example -(f d e a c b ) -@end example - -However, it is usually considered a bad idea for programmers to rely on -exactly what the order is. If the order for some superclasses is important, -it can be expressed directly in the class definition. - -The precedence list of a class can be obtained by the function -@code{class-precedence-list}. This function returns a ordered -list whose first element is the most specific class. For instance, - -@lisp -(class-precedence-list B) @result{} (#< B 401b97c8> - #< 401e4a10> - #< 4026a9d8>) -@end lisp - -However, this result is not too much readable; using the function -@code{class-name} yields a clearer result: - -@lisp -(map class-name (class-precedence-list B)) @result{} (B ) -@end lisp - -@node Generic functions -@subsection Generic functions - -A GOOPS method is like a Scheme procedure except that it is specialized -for a particular set of argument classes, and will only be used when the -actual arguments in a call match the classes in the method definition. - -@lisp -(define-method (+ (x ) (y )) - (string-append x y)) - -(+ "abc" "de") @result{} "abcde" -@end lisp - -A method is not formally associated with any single class (as it is in -many other object oriented languages), because a method can be -specialized for a combination of several classes. If you've studied -object orientation in non-Lispy languages, you may remember discussions -such as whether a method to stretch a graphical image around a surface -should be a method of the image class, with a surface as a parameter, or -a method of the surface class, with an image as a parameter. In GOOPS -you'd just write - -@lisp -(define-method (stretch (im ) (sf )) - ...) -@end lisp - -@noindent -and the question of which class the method is more associated with does -not need answering. - -A generic function is a collection of methods with the same name but -different sets of specializing argument classes. - -@menu -* Generic functions and methods:: -* Next-method:: -* Example:: -@end menu - -@node Generic functions and methods -@subsubsection Generic functions and methods - -@c \label{gf-n-methods} -Neither @goops{} nor CLOS use the message mechanism for methods as most -Object Oriented language do. Instead, they use the notion of -@dfn{generic functions}. A generic function can be seen as a methods -``tanker''. When the evaluator requested the application of a generic -function, all the methods of this generic function will be grabbed and -the most specific among them will be applied. We say that a method -@var{M} is @emph{more specific} than a method @var{M'} if the class of -its parameters are more specific than the @var{M'} ones. To be more -precise, when a generic function must be ``called'' the system will: - -@cindex generic function -@enumerate -@item -search among all the generic function those which are applicable -@item -sort the list of applicable methods in the ``most specific'' order -@item -call the most specific method of this list (i.e. the first method of -the sorted methods list). -@end enumerate - -The definition of a generic function is done with the -@code{define-generic} macro. Definition of a new method is done with the -@code{define-method} macro. Note that @code{define-method} automatically -defines the generic function if it has not been defined -before. Consequently, most of the time, the @code{define-generic} needs -not be used. -@findex define-generic -@findex define-method -Consider the following definitions: - -@lisp -(define-generic G) -(define-method (G (a ) b) 'integer) -(define-method (G (a ) b) 'real) -(define-method (G a b) 'top) -@end lisp - -The @code{define-generic} call defines @var{G} as a generic -function. Note that the signature of the generic function is not given -upon definition, contrarily to CLOS. This will permit methods with -different signatures for a given generic function, as we shall see -later. The three next lines define methods for the @var{G} generic -function. Each method uses a sequence of @dfn{parameter specializers} -that specify when the given method is applicable. A specializer permits -to indicate the class a parameter must belong to (directly or -indirectly) to be applicable. If no specializer is given, the system -defaults it to @code{}. Thus, the first method definition is -equivalent to - -@cindex parameter specializers -@lisp -(define-method (G (a ) (b )) 'integer) -@end lisp - -Now, let us look at some possible calls to generic function @var{G}: - -@lisp -(G 2 3) @result{} integer -(G 2 #t) @result{} integer -(G 1.2 'a) @result{} real -@c (G #3 'a) @result{} real @c was {\sharpsign} -(G #t #f) @result{} top -(G 1 2 3) @result{} error (since no method exists for 3 parameters) -@end lisp - -The preceding methods use only one specializer per parameter list. Of -course, each parameter can use a specializer. In this case, the -parameter list is scanned from left to right to determine the -applicability of a method. Suppose we declare now - -@lisp -(define-method (G (a ) (b )) 'integer-number) -(define-method (G (a ) (b )) 'integer-real) -(define-method (G (a ) (b )) 'integer-integer) -(define-method (G a (b )) 'top-number) -@end lisp - -In this case, - -@lisp -(G 1 2) @result{} integer-integer -(G 1 1.0) @result{} integer-real -(G 1 #t) @result{} integer -(G 'a 1) @result{} top-number -@end lisp - -@node Next-method -@subsubsection Next-method - -When you call a generic function, with a particular set of arguments, -GOOPS builds a list of all the methods that are applicable to those -arguments and orders them by how closely the method definitions match -the actual argument types. It then calls the method at the top of this -list. If the selected method's code wants to call on to the next method -in this list, it can do so by using @code{next-method}. - -@lisp -(define-method (Test (a )) (cons 'integer (next-method))) -(define-method (Test (a )) (cons 'number (next-method))) -(define-method (Test a) (list 'top)) -@end lisp - -With these definitions, - -@lisp -(Test 1) @result{} (integer number top) -(Test 1.0) @result{} (number top) -(Test #t) @result{} (top) -@end lisp - -@code{next-method} is always called as just @code{(next-method)}. The -arguments for the next method call are always implicit, and always the -same as for the original method call. - -If you want to call on to a method with the same name but with a -different set of arguments (as you might with overloaded methods in C++, -for example), you do not use @code{next-method}, but instead simply -write the new call as usual: - -@lisp -(define-method (Test (a ) min max) - (if (and (>= a min) (<= a max)) - (display "Number is in range\n")) - (Test a)) - -(Test 2 1 10) -@print{} -Number is in range -@result{} -(integer number top) -@end lisp - -(You should be careful in this case that the @code{Test} calls do not -lead to an infinite recursion, but this consideration is just the same -as in Scheme code in general.) - -@node Example -@subsubsection Example - -In this section we shall continue to define operations on the @code{} -class defined in Figure@ 2. Suppose that we want to use it to implement -complex numbers completely. For instance a definition for the addition of -two complexes could be - -@lisp -(define-method (new-+ (a ) (b )) - (make-rectangular (+ (real-part a) (real-part b)) - (+ (imag-part a) (imag-part b)))) -@end lisp - -To be sure that the @code{+} used in the method @code{new-+} is the standard -addition we can do: - -@lisp -(define-generic new-+) - -(let ((+ +)) - (define-method (new-+ (a ) (b )) - (make-rectangular (+ (real-part a) (real-part b)) - (+ (imag-part a) (imag-part b))))) -@end lisp - -The @code{define-generic} ensures here that @code{new-+} will be defined -in the global environment. Once this is done, we can add methods to the -generic function @code{new-+} which make a closure on the @code{+} -symbol. A complete writing of the @code{new-+} methods is shown in -Figure@ 3. - -@example -@group -@lisp -(define-generic new-+) - -(let ((+ +)) - - (define-method (new-+ (a ) (b )) (+ a b)) - - (define-method (new-+ (a ) (b )) - (make-rectangular (+ a (real-part b)) (imag-part b))) - - (define-method (new-+ (a ) (b )) - (make-rectangular (+ (real-part a) b) (imag-part a))) - - (define-method (new-+ (a ) (b )) - (make-rectangular (+ (real-part a) (real-part b)) - (+ (imag-part a) (imag-part b)))) - - (define-method (new-+ (a )) a) - - (define-method (new-+) 0) - - (define-method (new-+ . args) - (new-+ (car args) - (apply new-+ (cdr args))))) - -(set! + new-+) -@end lisp - -@center @emph{Fig 3: Extending @code{+} for dealing with complex numbers} -@end group -@end example - -@sp 3 -We use here the fact that generic function are not obliged to have the -same number of parameters, contrarily to CLOS. The four first methods -implement the dyadic addition. The fifth method says that the addition -of a single element is this element itself. The sixth method says that -using the addition with no parameter always return 0. The last method -takes an arbitrary number of parameters@footnote{The parameter list for -a @code{define-method} follows the conventions used for Scheme -procedures. In particular it can use the dot notation or a symbol to -denote an arbitrary number of parameters}. This method acts as a kind -of @code{reduce}: it calls the dyadic addition on the @emph{car} of the -list and on the result of applying it on its rest. To finish, the -@code{set!} permits to redefine the @code{+} symbol to our extended -addition. - -@sp 3 -To terminate our implementation (integration?) of complex numbers, we can -redefine standard Scheme predicates in the following manner: - -@lisp -(define-method (complex? c ) #t) -(define-method (complex? c) #f) - -(define-method (number? n ) #t) -(define-method (number? n) #f) -@dots{} -@dots{} -@end lisp - -Standard primitives in which complex numbers are involved could also be -redefined in the same manner. - diff --git a/doc/ref/goops.texi b/doc/ref/goops.texi index a0494db52..1160e5c3e 100644 --- a/doc/ref/goops.texi +++ b/doc/ref/goops.texi @@ -28,11 +28,23 @@ protocol --- which means that @goops{}'s core operations are themselves defined as methods on relevant classes, and can be customised by overriding or redefining those methods. +To start using @goops{} you first need to import the @code{(oop goops)} +module. You can do this at the Guile REPL by evaluating: + +@lisp +(use-modules (oop goops)) +@end lisp +@findex (oop goops) + @menu * Copyright Notice:: -* Tutorial:: -* Defining New Classes:: -* Creating Instances:: +* Class Definition:: +* Instance Creation:: +* Slot Options:: +* Slot Description Example:: +* Methods and Generic Functions:: +* Inheritance:: +* Class Options:: * Accessing Slots:: * Generic Functions and Accessors:: * Adding Methods to Generic Functions:: @@ -67,17 +79,30 @@ The material has been adapted for use in Guile, with the author's permission. -@node Tutorial -@section Tutorial -@include goops-tutorial.texi +@node Class Definition +@section Class Definition +A new class is defined with the @code{define-class} syntax: -@node Defining New Classes -@section Defining New Classes +@findex define-class +@cindex class +@lisp +(define-class @var{class} (@var{superclass} @dots{}) + @var{slot-description} @dots{} + @var{class-option} @dots{}) +@end lisp -New classes are defined using the @code{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 class options. +@var{class} is the class being defined. The list of @var{superclass}es +specifies which existing classes, if any, to inherit slots and +properties from. @dfn{Slots} hold per-instance@footnote{Usually --- but +see also the @code{#:allocation} slot option.} data, for instances of +that class --- like ``fields'' or ``member variables'' in other object +oriented systems. Each @var{slot-description} gives the name of a slot +and optionally some ``properties'' of this slot; for example its initial +value, the name of a function which will access its value, and so on. +Slot descriptions and inheritance are discussed more below. For class +options, see @ref{Class Options}. +@cindex slot @deffn syntax define-class name (super @dots{}) slot-definition @dots{} . options Define a class called @var{name} that inherits from @var{super}s, with @@ -101,59 +126,136 @@ odd-numbered elements are the corresponding values for those keywords. keywords and corresponding values. @end deffn -Example 1. Define a class that combines two pre-existing classes by -inheritance but adds no new slots. +As an example, let us define a type for representing a complex number +in terms of two real numbers.@footnote{Of course Guile already +provides complex numbers, and @code{} is in fact a predefined +class in GOOPS; but the definition here is still useful as an +example.} This can be done with the following class definition: -@example -(define-class ( )) -@end example +@lisp +(define-class () + r i) +@end lisp -Example 2. Define a @code{regular-polygon} class with slots for side -length and number of sides. The slots have default values and can be -accessed via the generic functions @code{side-length} and -@code{num-sides}. - -@example -(define-class () - (sl #:init-value 1 #:accessor side-length) - (ns #:init-value 5 #:accessor num-sides)) -@end example - -Example 3. Define a class whose behavior (and that of its instances) is -customized via an application-defined metaclass. - -@example -(define-class () - (s #:init-value #f #:accessor state) - ... - #:metaclass ) -@end example +This binds the variable @code{} to a new class whose +instances will contain two slots. These slots are called @code{r} and +@code{i} and will hold the real and imaginary parts of a complex +number. Note that this class inherits from @code{}, which is a +predefined class.@footnote{@code{} is the direct superclass of +the predefined class @code{}; @code{} is the +superclass of @code{}, and @code{} is the superclass of +@code{}.} The possible slot and class options are described in the following -subsections. +sections. + + +@node Instance Creation +@section Instance Creation and Slot Access + +An instance (or object) of a defined class can be created with +@code{make}. @code{make} takes one mandatory parameter, which is the +class of the instance to create, and a list of optional arguments that +will be used to initialize the slots of the new instance. For instance +the following form + +@findex make +@cindex instance +@lisp +(define c (make )) +@end lisp + +@noindent +creates a new @code{} object and binds it to the Scheme +variable @code{c}. + +@deffn generic make +@deffnx method make (class ) . initargs +Create and return a new instance of class @var{class}, initialized using +@var{initargs}. + +In theory, @var{initargs} can have any structure that is understood by +whatever methods get applied when the @code{initialize} generic function +is applied to the newly allocated instance. + +In practice, specialized @code{initialize} methods would normally call +@code{(next-method)}, and so eventually the standard GOOPS +@code{initialize} methods are applied. These methods expect +@var{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 @code{#:init-keyword} option (@pxref{Slot +Options,, init-keyword}). Other keyword value pairs can only be +processed by an @code{initialize} method that is specialized for the new +instance's class. Any unprocessed keyword value pairs are ignored. +@end deffn + +@deffn generic make-instance +@deffnx method make-instance (class ) . initargs +@code{make-instance} is an alias for @code{make}. +@end deffn + +The slots of the new complex number can be accessed using +@code{slot-ref} and @code{slot-set!}. @code{slot-set!} sets the value +of an object slot and @code{slot-ref} retrieves it. + +@findex slot-set! +@findex slot-ref +@lisp +@group +(slot-set! c 'r 10) +(slot-set! c 'i 3) +(slot-ref c 'r) @result{} 10 +(slot-ref c 'i) @result{} 3 +@end group +@end lisp + +The @code{(oop goops describe)} module provides a @code{describe} +function that is useful for seeing all the slots of an object; it prints +the slots and their values to standard output. + +@lisp +(describe c) +@print{} +#< 401d8638> is an instance of class +Slots are: + r = 10 + i = 3 +@end lisp -@menu -* Slot Options:: -* Class Options:: -@end menu @node Slot Options -@subsection Slot Options +@section Slot Options + +When specifying a slot (in a @code{(define-class @dots{})} form), +various options can be specified in addition to the slot's name. Each +option is specified by a keyword. The list of possible keywords is +as follows. @deffn {slot option} #:init-value init-value @deffnx {slot option} #:init-form init-form @deffnx {slot option} #:init-thunk init-thunk @deffnx {slot option} #:init-keyword init-keyword These options provide various ways to specify how to initialize the -slot's value at instance creation time. @var{init-value} is a fixed -value (shared across all new instances of the class). -@var{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. @var{init-form} is an unevaluated expression that gets -evaluated when a new instance is created and should return the desired -initial slot value. @var{init-keyword} is a keyword that can be used -to pass an initial slot value to @code{make} when creating a new -instance. +slot's value at instance creation time. +@cindex default slot value + +@var{init-value} specifies a fixed initial slot value (shared across all +new instances of the class). + +@var{init-thunk} specifies a thunk that will provide a default value for +the slot. The thunk is called when a new instance is created and should +return the desired initial slot value. + +@var{init-form} specifies a form that, when evaluated, will return +an initial value for the slot. The form is evaluated each time that +an instance of the class is created, in the lexical environment of the +containing @code{define-class} expression. + +@var{init-keyword} specifies a keyword that can be used to pass an +initial slot value to @code{make} when creating a new instance. Note that, since an @code{init-value} value is shared across all instances of a class, you should only use it when the initial value is @@ -286,10 +388,11 @@ read-only, write-only and read-write slots would typically use only respectively. @end itemize -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 @code{define-class} that contains -the slot definition. For details, see @ref{Generic Function Internals,, +The binding of the specified names is done in the environment of the +@code{define-class} expression. If the names are already bound (in that +environment) to values that cannot be upgraded to generic functions, +those values are overwritten when the @code{define-class} expression is +evaluated. For more detail, see @ref{Generic Function Internals,, ensure-generic}. @end deffn @@ -300,18 +403,24 @@ the slot. Possible values for @var{allocation} are @itemize @bullet @item @code{#:instance} +@findex #:instance Indicates that GOOPS should create separate storage for this slot in -each new instance of the containing class (and its subclasses). +each new instance of the containing class (and its subclasses). This is +the default. @item @code{#:class} +@findex #: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 @var{C} with allocation @code{#:class} is shared by all @var{instance}s for which @code{(is-a? @var{instance} @var{c})}. +This permits defining a kind of global variable which can be accessed +only by (in)direct instances of the class which defines the slot. @item @code{#:each-subclass} +@findex #:each-subclass Indicates that GOOPS should create storage for this slot that is shared by all @emph{direct} instances of the containing class, and that whenever a subclass of the containing class is defined, GOOPS should @@ -322,14 +431,15 @@ instances of the subclass. In other words, a slot with allocation @item @code{#:virtual} +@findex #:slot-set! +@findex #:slot-ref +@findex #:virtual Indicates that GOOPS should not allocate storage for this slot. The slot definition must also include the @code{#:slot-ref} and @code{#:slot-set!} options to specify how to reference and set the value -for this slot. +for this slot. See the example below. @end itemize -The default value is @code{#:instance}. - Slot allocation options are processed when defining a new class by the generic function @code{compute-get-n-set}, which is specialized by the class's metaclass. Hence new types of slot allocation can be @@ -349,8 +459,555 @@ taking two parameters - @var{instance} and @var{new-val} - that sets the slot value to @var{new-val}. @end deffn +@node Slot Description Example +@section Illustrating Slot Description + +To illustrate slot description, we can redefine the @code{} +class seen before. A definition could be: + +@lisp +(define-class () + (r #:init-value 0 #:getter get-r #:setter set-r! #:init-keyword #:r) + (i #:init-value 0 #:getter get-i #:setter set-i! #:init-keyword #:i)) +@end lisp + +@noindent +With this definition, the @code{r} and @code{i} slots are set to 0 by +default, and can be initialised to other values by calling @code{make} +with the @code{#:r} and @code{#:i} keywords. Also the generic functions +@code{get-r}, @code{set-r!}, @code{get-i} and @code{set-i!} are +automatically defined to read and write the slots. + +@lisp +(define c1 (make #:r 1 #:i 2)) +(get-r c1) @result{} 1 +(set-r! c1 12) +(get-r c1) @result{} 12 +(define c2 (make #:r 2)) +(get-r c2) @result{} 2 +(get-i c2) @result{} 0 +@end lisp + +Accessors can both read and write a slot. So, another definition of the +@code{} class, using the @code{#:accessor} option, could be: + +@findex set! +@lisp +(define-class () + (r #:init-value 0 #:accessor real-part #:init-keyword #:r) + (i #:init-value 0 #:accessor imag-part #:init-keyword #:i)) +@end lisp + +@noindent +With this definition, the @code{r} slot can be read with: +@lisp +(real-part c) +@end lisp +@noindent +and set with: +@lisp +(set! (real-part c) new-value) +@end lisp + +Suppose now that we want to manipulate complex numbers with both +rectangular and polar coordinates. One solution could be to have a +definition of complex numbers which uses one particular representation +and some conversion functions to pass from one representation to the +other. A better solution is to use virtual slots, like this: + +@lisp +(define-class () + ;; True slots use rectangular coordinates + (r #:init-value 0 #:accessor real-part #:init-keyword #:r) + (i #:init-value 0 #:accessor imag-part #:init-keyword #:i) + ;; Virtual slots access do the conversion + (m #:accessor magnitude #:init-keyword #:magn + #:allocation #:virtual + #:slot-ref (lambda (o) + (let ((r (slot-ref o 'r)) (i (slot-ref o 'i))) + (sqrt (+ (* r r) (* i i))))) + #:slot-set! (lambda (o m) + (let ((a (slot-ref o 'a))) + (slot-set! o 'r (* m (cos a))) + (slot-set! o 'i (* m (sin a)))))) + (a #:accessor angle #:init-keyword #:angle + #:allocation #:virtual + #:slot-ref (lambda (o) + (atan (slot-ref o 'i) (slot-ref o 'r))) + #:slot-set! (lambda(o a) + (let ((m (slot-ref o 'm))) + (slot-set! o 'r (* m (cos a))) + (slot-set! o 'i (* m (sin a))))))) + +@end lisp + +In this class definition, the magniture @code{m} and angle @code{a} +slots are virtual, and are calculated, when referenced, from the normal +(i.e. @code{#:allocation #:instance}) slots @code{r} and @code{i}, by +calling the function defined in the relevant @code{#:slot-ref} option. +Correspondingly, writing @code{m} or @code{a} leads to calling the +function defined in the @code{#:slot-set!} option. Thus the +following expression + +@findex #:slot-set! +@findex #:slot-ref +@lisp +(slot-set! c 'a 3) +@end lisp + +@noindent +permits to set the angle of the @code{c} complex number. + +@lisp +(define c (make #:r 12 #:i 20)) +(real-part c) @result{} 12 +(angle c) @result{} 1.03037682652431 +(slot-set! c 'i 10) +(set! (real-part c) 1) +(describe c) +@print{} +#< 401e9b58> is an instance of class +Slots are: + r = 1 + i = 10 + m = 10.0498756211209 + a = 1.47112767430373 +@end lisp + +Since initialization keywords have been defined for the four slots, we +can now define the standard Scheme primitives @code{make-rectangular} +and @code{make-polar}. + +@lisp +(define make-rectangular + (lambda (x y) (make #:r x #:i y))) + +(define make-polar + (lambda (x y) (make #:magn x #:angle y))) +@end lisp + + +@node Methods and Generic Functions +@section Methods and Generic Functions + +A GOOPS method is like a Scheme procedure except that it is specialized +for a particular set of argument classes, and will only be used when the +actual arguments in a call match the classes in the method definition. + +@lisp +(define-method (+ (x ) (y )) + (string-append x y)) + +(+ "abc" "de") @result{} "abcde" +@end lisp + +A method is not formally associated with any single class (as it is in +many other object oriented languages), because a method can be +specialized for a combination of several classes. If you've studied +object orientation in non-Lispy languages, you may remember discussions +such as whether a method to stretch a graphical image around a surface +should be a method of the image class, with a surface as a parameter, or +a method of the surface class, with an image as a parameter. In GOOPS +you'd just write + +@lisp +(define-method (stretch (im ) (sf )) + ...) +@end lisp + +@noindent +and the question of which class the method is more associated with does +not need answering. + +A generic function is a collection of methods with the same name but +different sets of specializing argument classes. + +@menu +* Generic functions and methods:: +* Next-method:: +* Example:: +@end menu + +@node Generic functions and methods +@subsection Generic functions and methods + +@c \label{gf-n-methods} +Neither @goops{} nor CLOS use the message mechanism for methods as most +Object Oriented language do. Instead, they use the notion of +@dfn{generic functions}. A generic function can be seen as a methods +``tanker''. When the evaluator requested the application of a generic +function, all the methods of this generic function will be grabbed and +the most specific among them will be applied. We say that a method +@var{M} is @emph{more specific} than a method @var{M'} if the class of +its parameters are more specific than the @var{M'} ones. To be more +precise, when a generic function must be ``called'' the system will: + +@cindex generic function +@enumerate +@item +search among all the generic function those which are applicable +@item +sort the list of applicable methods in the ``most specific'' order +@item +call the most specific method of this list (i.e. the first method of +the sorted methods list). +@end enumerate + +The definition of a generic function is done with the +@code{define-generic} macro. Definition of a new method is done with the +@code{define-method} macro. Note that @code{define-method} automatically +defines the generic function if it has not been defined +before. Consequently, most of the time, the @code{define-generic} needs +not be used. +@findex define-generic +@findex define-method +Consider the following definitions: + +@lisp +(define-generic G) +(define-method (G (a ) b) 'integer) +(define-method (G (a ) b) 'real) +(define-method (G a b) 'top) +@end lisp + +The @code{define-generic} call defines @var{G} as a generic +function. Note that the signature of the generic function is not given +upon definition, contrarily to CLOS. This will permit methods with +different signatures for a given generic function, as we shall see +later. The three next lines define methods for the @var{G} generic +function. Each method uses a sequence of @dfn{parameter specializers} +that specify when the given method is applicable. A specializer permits +to indicate the class a parameter must belong to (directly or +indirectly) to be applicable. If no specializer is given, the system +defaults it to @code{}. Thus, the first method definition is +equivalent to + +@cindex parameter specializers +@lisp +(define-method (G (a ) (b )) 'integer) +@end lisp + +Now, let us look at some possible calls to generic function @var{G}: + +@lisp +(G 2 3) @result{} integer +(G 2 #t) @result{} integer +(G 1.2 'a) @result{} real +@c (G #3 'a) @result{} real @c was {\sharpsign} +(G #t #f) @result{} top +(G 1 2 3) @result{} error (since no method exists for 3 parameters) +@end lisp + +The preceding methods use only one specializer per parameter list. Of +course, each parameter can use a specializer. In this case, the +parameter list is scanned from left to right to determine the +applicability of a method. Suppose we declare now + +@lisp +(define-method (G (a ) (b )) 'integer-number) +(define-method (G (a ) (b )) 'integer-real) +(define-method (G (a ) (b )) 'integer-integer) +(define-method (G a (b )) 'top-number) +@end lisp + +In this case, + +@lisp +(G 1 2) @result{} integer-integer +(G 1 1.0) @result{} integer-real +(G 1 #t) @result{} integer +(G 'a 1) @result{} top-number +@end lisp + +@node Next-method +@subsection Next-method + +When you call a generic function, with a particular set of arguments, +GOOPS builds a list of all the methods that are applicable to those +arguments and orders them by how closely the method definitions match +the actual argument types. It then calls the method at the top of this +list. If the selected method's code wants to call on to the next method +in this list, it can do so by using @code{next-method}. + +@lisp +(define-method (Test (a )) (cons 'integer (next-method))) +(define-method (Test (a )) (cons 'number (next-method))) +(define-method (Test a) (list 'top)) +@end lisp + +With these definitions, + +@lisp +(Test 1) @result{} (integer number top) +(Test 1.0) @result{} (number top) +(Test #t) @result{} (top) +@end lisp + +@code{next-method} is always called as just @code{(next-method)}. The +arguments for the next method call are always implicit, and always the +same as for the original method call. + +If you want to call on to a method with the same name but with a +different set of arguments (as you might with overloaded methods in C++, +for example), you do not use @code{next-method}, but instead simply +write the new call as usual: + +@lisp +(define-method (Test (a ) min max) + (if (and (>= a min) (<= a max)) + (display "Number is in range\n")) + (Test a)) + +(Test 2 1 10) +@print{} +Number is in range +@result{} +(integer number top) +@end lisp + +(You should be careful in this case that the @code{Test} calls do not +lead to an infinite recursion, but this consideration is just the same +as in Scheme code in general.) + +@node Example +@subsection Example + +In this section we shall continue to define operations on the @code{} +class defined in Figure@ 2. Suppose that we want to use it to implement +complex numbers completely. For instance a definition for the addition of +two complexes could be + +@lisp +(define-method (new-+ (a ) (b )) + (make-rectangular (+ (real-part a) (real-part b)) + (+ (imag-part a) (imag-part b)))) +@end lisp + +To be sure that the @code{+} used in the method @code{new-+} is the standard +addition we can do: + +@lisp +(define-generic new-+) + +(let ((+ +)) + (define-method (new-+ (a ) (b )) + (make-rectangular (+ (real-part a) (real-part b)) + (+ (imag-part a) (imag-part b))))) +@end lisp + +The @code{define-generic} ensures here that @code{new-+} will be defined +in the global environment. Once this is done, we can add methods to the +generic function @code{new-+} which make a closure on the @code{+} +symbol. A complete writing of the @code{new-+} methods is shown in +Figure@ 3. + +@example +@group +@lisp +(define-generic new-+) + +(let ((+ +)) + + (define-method (new-+ (a ) (b )) (+ a b)) + + (define-method (new-+ (a ) (b )) + (make-rectangular (+ a (real-part b)) (imag-part b))) + + (define-method (new-+ (a ) (b )) + (make-rectangular (+ (real-part a) b) (imag-part a))) + + (define-method (new-+ (a ) (b )) + (make-rectangular (+ (real-part a) (real-part b)) + (+ (imag-part a) (imag-part b)))) + + (define-method (new-+ (a )) a) + + (define-method (new-+) 0) + + (define-method (new-+ . args) + (new-+ (car args) + (apply new-+ (cdr args))))) + +(set! + new-+) +@end lisp + +@center @emph{Fig 3: Extending @code{+} for dealing with complex numbers} +@end group +@end example + +@sp 3 +We use here the fact that generic function are not obliged to have the +same number of parameters, contrarily to CLOS. The four first methods +implement the dyadic addition. The fifth method says that the addition +of a single element is this element itself. The sixth method says that +using the addition with no parameter always return 0. The last method +takes an arbitrary number of parameters@footnote{The parameter list for +a @code{define-method} follows the conventions used for Scheme +procedures. In particular it can use the dot notation or a symbol to +denote an arbitrary number of parameters}. This method acts as a kind +of @code{reduce}: it calls the dyadic addition on the @emph{car} of the +list and on the result of applying it on its rest. To finish, the +@code{set!} permits to redefine the @code{+} symbol to our extended +addition. + +@sp 3 +To terminate our implementation (integration?) of complex numbers, we can +redefine standard Scheme predicates in the following manner: + +@lisp +(define-method (complex? c ) #t) +(define-method (complex? c) #f) + +(define-method (number? n ) #t) +(define-method (number? n) #f) +@dots{} +@dots{} +@end lisp + +Standard primitives in which complex numbers are involved could also be +redefined in the same manner. + + +@node Inheritance +@section Inheritance + +Here are some class definitions to help illustrate inheritance: + +@lisp +(define-class A () a) +(define-class B () b) +(define-class C () c) +(define-class D (A B) d a) +(define-class E (A C) e c) +(define-class F (D E) f) +@end lisp + +@code{A}, @code{B}, @code{C} have a null list of superclasses. In this +case, the system will replace the null list by a list which only +contains @code{}, the root of all the classes defined by +@code{define-class}. @code{D}, @code{E}, @code{F} use multiple +inheritance: each class inherits from two previously defined classes. +Those class definitions define a hierarchy which is shown in Figure@ 1. +In this figure, the class @code{} is also shown; this class is the +superclass of all Scheme objects. In particular, @code{} is the +superclass of all standard Scheme types. + +@example +@group +@iftex +@center @image{hierarchy,5in} +@end iftex +@ifnottex +@verbatiminclude hierarchy.txt +@end ifnottex + +@emph{Fig 1: A class hierarchy}@footnote{@code{}, which is the +direct subclass of @code{} and the direct superclass of +@code{}, has been omitted in this figure.} +@end group +@end example + +When a class has superclasses, its set of slots is calculated by taking +the union of its own slots and those of all its superclasses. Thus each +instance of D will have three slots, @code{a}, @code{b} and +@code{d}). The slots of a class can be discovered using the +@code{class-slots} primitive. For instance, + +@lisp +(class-slots A) @result{} ((a)) +(class-slots E) @result{} ((a) (e) (c)) +(class-slots F) @result{} ((e) (c) (b) (d) (a) (f)) +@end lisp + +@noindent +The ordering of the returned slots is not significant. + +@menu +* Class precedence list:: +@end menu + + +@node Class precedence list +@subsection Class precedence list + +A class may have more than one superclass. @footnote{This section is an +adaptation of Jeff Dalton's (J.Dalton@@ed.ac.uk) @cite{Brief +introduction to CLOS}} With single inheritance (one superclass), it is +easy to order the superclasses from most to least specific. This is the +rule: + +@display +@cartouche +Rule 1: Each class is more specific than its superclasses.@c was \bf +@end cartouche +@end display + +With multiple inheritance, ordering is harder. Suppose we have + +@lisp +(define-class X () + (x #:init-value 1)) + +(define-class Y () + (x #:init-value 2)) + +(define-class Z (X Y) + (@dots{})) +@end lisp + +In this case, the @code{Z} class is more specific than the @code{X} or +@code{Y} class for instances of @code{Z}. However, the @code{#:init-value} +specified in @code{X} and @code{Y} leads to a problem: which one +overrides the other? The rule in @goops{}, as in CLOS, is that the +superclasses listed earlier are more specific than those listed later. +So: + +@display +@cartouche +Rule 2: For a given class, superclasses listed earlier are more + specific than those listed later. +@end cartouche +@end display + +These rules are used to compute a linear order for a class and all its +superclasses, from most specific to least specific. This order is +called the ``class precedence list'' of the class. Given these two +rules, we can claim that the initial form for the @code{x} slot of +previous example is 1 since the class @code{X} is placed before @code{Y} +in class precedence list of @code{Z}. + +These two rules are not always enough to determine a unique order, +however, but they give an idea of how things work. Taking the @code{F} +class shown in Figure@ 1, the class precedence list is + +@example +(f d e a c b ) +@end example + +However, it is usually considered a bad idea for programmers to rely on +exactly what the order is. If the order for some superclasses is important, +it can be expressed directly in the class definition. + +The precedence list of a class can be obtained by the function +@code{class-precedence-list}. This function returns a ordered +list whose first element is the most specific class. For instance, + +@lisp +(class-precedence-list B) @result{} (#< B 401b97c8> + #< 401e4a10> + #< 4026a9d8>) +@end lisp + +However, this result is not too much readable; using the function +@code{class-name} yields a clearer result: + +@lisp +(map class-name (class-precedence-list B)) @result{} (B ) +@end lisp + + @node Class Options -@subsection Class Options +@section Class Options @deffn {class option} #:metaclass metaclass The @code{#:metaclass} class option specifies the metaclass of the class @@ -372,101 +1029,9 @@ If the @code{#:name} option is absent, GOOPS uses the first argument to @code{define-class} as the class name. @end deffn -@node Creating Instances -@section Creating Instances - -To create a new instance of any GOOPS class, use the generic function -@code{make} or @code{make-instance}, passing the required class and any -appropriate instance initialization arguments as keyword and value -pairs. Note that @code{make} and @code{make-instances} are aliases for -each other --- their behaviour is identical. - -@deffn generic make -@deffnx method make (class ) . initargs -Create and return a new instance of class @var{class}, initialized using -@var{initargs}. - -In theory, @var{initargs} can have any structure that is understood by -whatever methods get applied when the @code{initialize} generic function -is applied to the newly allocated instance. - -In practice, specialized @code{initialize} methods would normally call -@code{(next-method)}, and so eventually the standard GOOPS -@code{initialize} methods are applied. These methods expect -@var{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 @code{#:init-keyword} option (@pxref{Slot -Options,, init-keyword}). Other keyword value pairs can only be -processed by an @code{initialize} method that is specialized for the new -instance's class. Any unprocessed keyword value pairs are ignored. -@end deffn - -@deffn generic make-instance -@deffnx method make-instance (class ) . initargs -@code{make-instance} is an alias for @code{make}. -@end deffn - @node Accessing Slots @section 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 -subsubsections. For example, - -@example -(define-class () ;; Define a class with slots - (count #:init-value 0) ;; named "count" and "cache". - (cache #:init-value '()) - @dots{}) - -(define inst (make )) ;; 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))) -@end example - -If a slot definition includes a getter, setter or accessor function, -these can be used instead of @code{slot-ref} and @code{slot-set!} to -access the slot. - -@example -(define-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) - @dots{}) - -(define inst (make )) ;; 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" - @dots{}) ;; slot. -@end example - -Whichever of these methods is used to access slots, GOOPS always calls -the low-level @dfn{getter} and @dfn{setter} closures for the slot to get -and set its value. These closures make sure that the slot behaves -according to the @code{#:allocation} type that was specified in the slot -definition (@pxref{Slot Options,, allocation}). (For more about these -closures, see @ref{Customizing Class Definition,, compute-get-n-set}.) - @menu * Instance Slots:: * Class Slots:: @@ -908,9 +1473,9 @@ default method calls @code{goops-error} with an appropriate message. @section Redefining a Class Suppose that a class @code{} is defined using @code{define-class} -(@pxref{Defining New Classes,, define-class}), with slots that have +(@pxref{Class Definition,, define-class}), with slots that have accessor functions, and that an application has created several instances -of @code{} using @code{make} (@pxref{Creating Instances,, +of @code{} using @code{make} (@pxref{Instance Creation,, make}). What then happens if @code{} is redefined by calling @code{define-class} again? @@ -928,9 +1493,9 @@ GOOPS' default answer to this question is as follows. @item All existing direct instances of @code{} are converted to be instances of the new class. This is achieved by preserving the values -of slots that exist in both the old and new definitions, and initializing the -values of new slots in the usual way (@pxref{Creating Instances,, -make}). +of slots that exist in both the old and new definitions, and +initializing the values of new slots in the usual way (@pxref{Instance +Creation,, make}). @item All existing subclasses of @code{} are redefined, as though @@ -1490,10 +2055,8 @@ GOOPS' power, by customizing the behaviour of GOOPS itself. * Metaobjects and the Metaobject Protocol:: * Terminology:: * MOP Specification:: -* Class Definition:: * Class Definition Internals:: * Customizing Class Definition:: -* Instance Creation:: * Customizing Instance Creation:: * Class Redefinition:: * Method Definition:: @@ -1824,8 +2387,8 @@ effects what the caller expects to get as the applied method's return value. @end itemize -@node Class Definition -@subsection Class Definition +@node Class Definition Internals +@subsection Class Definition Internals @code{define-class} (syntax) @@ -1957,9 +2520,6 @@ to the generic function named by the slot definition's @code{#:setter} or @code{#:accessor} option. @end itemize -@node Class Definition Internals -@subsection Class Definition Internals - @code{define-class} expands to an expression which @itemize @bullet @@ -1983,7 +2543,7 @@ handles the redefinition by invoking @code{class-redefinition} Return a newly created class that inherits from @var{super}s, with direct slots defined by @var{slot-definition}s and class options @var{options}. For the format of @var{slot-definition}s and -@var{options}, see @ref{Defining New Classes,, define-class}. +@var{options}, see @ref{Class Definition,, define-class}. @end deffn @noindent @code{class} expands to an expression which @@ -2004,8 +2564,8 @@ evaluated parameters. @deffn procedure make-class supers slots . options Return a newly created class that inherits from @var{supers}, with direct slots defined by @var{slots} and class options @var{options}. -For the format of @var{slots} and @var{options}, see @ref{Defining New -Classes,, define-class}, except note that for @code{make-class}, +For the format of @var{slots} and @var{options}, see @ref{Class +Definition,, define-class}, except note that for @code{make-class}, @var{slots} and @var{options} are separate list parameters: @var{slots} here is a list of slot definitions. @end deffn @@ -2206,8 +2766,8 @@ behaviour, by not calling @code{(next-method)} at all, but more typically it would perform additional class initialization steps before and/or after calling @code{(next-method)} for the standard behaviour. -@node Instance Creation -@subsection Instance Creation +@node Customizing Instance Creation +@subsection Customizing Instance Creation @code{make . @var{initargs}} (method) @@ -2227,9 +2787,6 @@ instance in whatever sense is appropriate for its class. The method's return value is ignored. @end itemize -@node Customizing Instance Creation -@subsection Customizing Instance Creation - @code{make} itself is a generic function. Hence the @code{make} invocation itself can be customized in the case where the new instance's metaclass is more specialized than the default @code{}, by