diff options
Diffstat (limited to 'doc/ref/goops.texi')
-rw-r--r-- | doc/ref/goops.texi | 850 |
1 files changed, 355 insertions, 495 deletions
diff --git a/doc/ref/goops.texi b/doc/ref/goops.texi index 452c88b6b..362a6e371 100644 --- a/doc/ref/goops.texi +++ b/doc/ref/goops.texi @@ -48,7 +48,6 @@ module. You can do this at the Guile REPL by evaluating: * GOOPS Error Handling:: * GOOPS Object Miscellany:: * The Metaobject Protocol:: -* Class Options:: * Redefining a Class:: * Changing the Class of an Instance:: @end menu @@ -94,8 +93,8 @@ 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}. +Class options, slot descriptions and inheritance are discussed more +below. @cindex slot @deffn syntax define-class name (super @dots{}) slot-definition @dots{} . options @@ -140,8 +139,28 @@ the predefined class @code{<complex>}; @code{<complex>} is the superclass of @code{<real>}, and @code{<real>} is the superclass of @code{<integer>}.} -The possible slot and class options are described in the following -sections. +Slot options are described in the next section. The possible class +options are as follows. + +@deffn {class option} #:metaclass metaclass +The @code{#:metaclass} class option specifies the metaclass of the class +being defined. @var{metaclass} must be a class that inherits from +@code{<class>}. For the use of metaclasses, see @ref{Metaobjects and +the Metaobject Protocol} and @ref{Metaclasses}. + +If the @code{#:metaclass} option is absent, GOOPS reuses or constructs a +metaclass for the new class by calling @code{ensure-metaclass} +(@pxref{Class Definition Protocol,, ensure-metaclass}). +@end deffn + +@deffn {class option} #:name name +The @code{#: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 @code{#:name} option is absent, GOOPS uses the first argument to +@code{define-class} as the class name. +@end deffn @node Instance Creation @@ -1756,7 +1775,7 @@ as the Guile primitive @code{write} and @code{display} functions. In addition to the cases mentioned, you can of course define @code{write} and @code{display} methods for your own classes, to -customize how they are printed. +customize how instances of those classes are printed. @node The Metaobject Protocol @@ -1775,24 +1794,21 @@ So let's plunge in. GOOPS is based on a ``metaobject protocol'' (aka 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 MOP is and how it works. On the other hand, -the MOP underlies even very simple customizations --- such as defining -an @code{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. +The MOP underlies many possible GOOPS customizations --- such as +defining an @code{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 at a deeper level, understanding the MOP is a key part of +understanding GOOPS, and of taking full advantage of GOOPS' power, by +customizing the behaviour of GOOPS itself. @menu * Metaobjects and the Metaobject Protocol:: -* Terminology:: +* Metaclasses:: * MOP Specification:: -* Class Definition Internals:: +* Instance Creation Protocol:: +* Class Definition Protocol:: * Customizing Class Definition:: -* Customizing Instance Creation:: -* Class Redefinition:: * Method Definition:: * Method Definition Internals:: * Generic Function Internals:: @@ -1826,7 +1842,7 @@ 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 +The ``metaobject protocol'' (or ``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. @@ -1852,7 +1868,7 @@ superclasses, slot definitions and class options that were specified in the @code{define-class} form. @item -@code{make} allocates memory for the new instance, and then invokes the +@code{make} allocates memory for the new instance, and invokes the @code{initialize} generic function to initialize the new instance's slots. @@ -1863,8 +1879,8 @@ performs the slot calculation. @end itemize In other words, rather than being hardcoded in @code{define-class}, the -behaviour of class definition is encapsulated by generic function -methods that are specialized for the class @code{<class>}. +default behaviour of class definition is encapsulated by generic +function methods that are specialized for the class @code{<class>}. It is possible to create a new class that inherits from @code{<class>}, which is called a ``metaclass'', and to write a new @code{initialize} @@ -1895,19 +1911,8 @@ Each following section covers a particular area of GOOPS functionality, and describes the generic functions that are relevant for customization of that area. -@node Terminology -@subsection 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. - -@subsubheading Metaclass +@node Metaclasses +@subsection Metaclasses A @dfn{metaclass} is the class of an object which represents a GOOPS class. Put more succinctly, a metaclass is a class's class. @@ -1923,30 +1928,29 @@ at what happens when a new class is created using @code{define-class}: (define-class <my-class> (<object>) . slots) @end example -GOOPS actually expands the @code{define-class} form to something like -this +@noindent +Guile expands this to something like: @example (define <my-class> (class (<object>) . slots)) @end example -and thence to +@noindent +which in turn expands to: @example (define <my-class> (make <class> #:supers (list <object>) #:slots slots)) @end example -In other words, the value of @code{<my-class>} is in fact an instance of -the class @code{<class>} with slot values specifying the superclasses -and slot definitions for the class @code{<my-class>}. (@code{#:supers} -and @code{#:slots} are initialization keywords for the @code{dsupers} -and @code{dslots} slots of the @code{<class>} class.) +As this expansion makes clear, the resulting value of @code{<my-class>} +is an instance of the class @code{<class>} with slot values specifying +the superclasses and slot definitions for the class @code{<my-class>}. +(@code{#:supers} and @code{#:slots} are initialization keywords for the +@code{dsupers} and @code{dslots} slots of the @code{<class>} class.) -In order to take advantage of the full power of the GOOPS metaobject -protocol (@pxref{MOP Specification}), it is sometimes desirable to -create a new class with a metaclass other than the default -@code{<class>}. This is done by writing: +Now suppose that you want to define a new class with a metaclass other +than the default @code{<class>}. This is done by writing: @example (define-class <my-class2> (<object>) @@ -1954,7 +1958,8 @@ create a new class with a metaclass other than the default #:metaclass <my-metaclass>) @end example -GOOPS expands this to something like: +@noindent +and Guile expands @emph{this} to something like: @example (define <my-class2> @@ -1991,91 +1996,12 @@ relationships between @code{my-object}, @code{<my-class2>}, The class of @code{my-object} is @code{<my-class2>}. @item -The metaclass of @code{my-object} is @code{<my-metaclass>}. - -@item The class of @code{<my-class2>} is @code{<my-metaclass>}. @item -The metaclass of @code{<my-class2>} is @code{<class>}. - -@item The class of @code{<my-metaclass>} is @code{<class>}. - -@item -The metaclass of @code{<my-metaclass>} is @code{<class>}. - -@item -@code{<my-class2>} is not a metaclass, since it is does not inherit from -@code{<class>}. - -@item -@code{<my-metaclass>} is a metaclass, since it inherits from -@code{<class>}. @end itemize -@subsubheading Class Precedence List - -The @dfn{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 @code{<top>}. - -For example, given this inheritance hierarchy: - -@example -(define-class <invertebrate> (<object>) @dots{}) -(define-class <echinoderm> (<invertebrate>) @dots{}) -(define-class <starfish> (<echinoderm>) @dots{}) -@end example - -the class precedence list of <starfish> would be - -@example -(<starfish> <echinoderm> <invertebrate> <object> <top>) -@end example - -With multiple inheritance, the algorithm is a little more complicated. -A full description is provided by the GOOPS Tutorial: see @ref{Class -Precedence List}. - -``Class precedence list'' is often abbreviated, in documentation and -Scheme variable names, to @dfn{cpl}. - -@subsubheading Accessor - -An @dfn{accessor} is a generic function with both reference and setter -methods. - -@example -(define-accessor perimeter) -@end example - -Reference methods for an accessor are defined in the same way as generic -function methods. - -@example -(define-method (perimeter (s <square>)) - (* 4 (side-length s))) -@end example - -Setter methods for an accessor are defined by specifying ``(setter -<accessor-name>)'' as the first parameter of the @code{define-method} -call. - -@example -(define-method ((setter perimeter) (s <square>) (n <number>)) - (set! (side-length s) (/ n 4))) -@end example - -Once an appropriate setter method has been defined in this way, it can -be invoked using the generalized @code{set!} syntax, as in: - -@example -(set! (perimeter s1) 18.3) -@end example @node MOP Specification @subsection MOP Specification @@ -2085,22 +2011,17 @@ customizable generic function invocations that can be made by the standard GOOPS syntax, procedures and methods, and to explain the protocol for customizing such invocations. -A generic function invocation is customizable if the types of the arguments -to which it is applied are not all determined by the lexical context in -which the invocation appears. For example, +A generic function invocation is customizable if the types of the +arguments to which it is applied are not completely determined by the +lexical context in which the invocation appears. For example, the +@code{(initialize @var{instance} @var{initargs})} invocation in the +default @code{make-instance} method is customizable, because the type of +the @code{@var{instance}} argument is determined by the class that was +passed to @code{make-instance}. -@itemize @bullet -@item -the @code{(initialize @var{instance} @var{initargs})} invocation in the -default @code{make-instance} method is customizable, because the type of the -@code{@var{instance}} argument is determined by the class that was passed to -@code{make-instance}. - -@item -the @code{(make <generic> #:name ',name)} invocation in @code{define-generic} -is not customizable, because all of its arguments have lexically determined -types. -@end itemize +(Whereas --- to give a counter-example --- the @code{(make <generic> +#:name ',name)} invocation in @code{define-generic} is not customizable, +because all of its arguments have lexically determined types.) When using this rule to decide whether a given generic function invocation is customizable, we ignore arguments that are expected to be handled in @@ -2121,140 +2042,174 @@ effects what the caller expects to get as the applied method's return value. @end itemize -@node Class Definition Internals -@subsection Class Definition Internals -@code{define-class} (syntax) +@node Instance Creation Protocol +@subsection Instance Creation Protocol + +@code{make <class> . @var{initargs}} (method) @itemize @bullet @item -@code{class} (syntax) +@code{allocate-instance @var{class} @var{initargs}} (generic) + +The applied @code{allocate-instance} method should allocate storage for +a new instance of class @var{class} and return the uninitialized instance. -@itemize @bullet @item -@code{make-class} (procedure) +@code{initialize @var{instance} @var{initargs}} (generic) + +@var{instance} is the uninitialized instance returned by +@code{allocate-instance}. The applied method should initialize the new +instance in whatever sense is appropriate for its class. The method's +return value is ignored. +@end itemize + +@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{<class>}, by +defining a @code{make} method that is specialized to that metaclass. + +Normally, however, the method for classes with metaclass @code{<class>} +will be applied. This method calls two generic functions: @itemize @bullet @item -@code{make @var{metaclass} @dots{}} (generic) +(allocate-instance @var{class} . @var{initargs}) -@var{metaclass} is the metaclass of the class being defined, either -taken from the @code{#:metaclass} class option or computed by -@code{ensure-metaclass}. The applied method must create and return the -fully initialized class metaobject for the new class definition. +@item +(initialize @var{instance} . @var{initargs}) @end itemize -@end itemize +@code{allocate-instance} allocates storage for and returns the new +instance, uninitialized. You might customize @code{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 @code{allocate-instance} method, specialized to that +metaclass, which calls a Guile primitive C function (or FFI code), 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 @code{make} and +@code{initialize}, so that GOOPS knows how to make classes from the +other system, access instance slots, and so on. + +@code{initialize} initializes the instance that is returned by +@code{allocate-instance}. The standard GOOPS methods perform +initializations appropriate to the instance class. + +@itemize @bullet +@item +At the least specialized level, the method for instances of type +@code{<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 @var{initargs}. @item -@code{class-redefinition @var{old-class} @var{new-class}} (generic) +The method for instances of type @code{<class>} calls +@code{(next-method)}, then performs the class initializations described +in @ref{Class Definition Protocol}. -@code{define-class} calls @code{class-redefinition} if the variable -specified by its first argument already held a GOOPS class definition. -@var{old-class} and @var{new-class} are the old and new class metaobjects. -The applied method should perform whatever is necessary to handle the -redefinition, and should return the class metaobject that is to be bound -to @code{define-class}'s variable. The default class redefinition -protocol is described in @ref{Class Redefinition}. +@item +and so on for generic functions, methods, operator classes @dots{} @end itemize -The @code{(make @var{metaclass} @dots{})} invocation above will create -an class metaobject with metaclass @var{metaclass}. By default, this -metaobject will be initialized by the @code{initialize} method that is -specialized for instances of type @code{<class>}. +Similarly, you can customize the initialization of instances of any +application-defined class by defining an @code{initialize} method +specialized to that class. -@code{initialize <class> @var{initargs}} (method) +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 @code{#:init-thunk} keywords +and closures in the slot definitions, it may be neater to write an +@code{initialize} method for the class that queries the database once +and initializes all the dependent slot values according to the results. + + +@node Class Definition Protocol +@subsection Class Definition Protocol + +Here is a summary diagram of the syntax, procedures and generic +functions that may be involved in class definition. + +@noindent +@code{define-class} (syntax) @itemize @bullet @item -@code{compute-cpl @var{class}} (generic) +@code{class} (syntax) -The applied method should compute and return the class precedence list -for @var{class} as a list of class metaobjects. When @code{compute-cpl} -is called, the following @var{class} metaobject slots have all been -initialized: @code{name}, @code{direct-supers}, @code{direct-slots}, -@code{direct-subclasses} (empty), @code{direct-methods}. The value -returned by @code{compute-cpl} will be stored in the @code{cpl} slot. +@itemize @bullet +@item +@code{make-class} (procedure) +@itemize @bullet @item -@code{compute-slots @var{class}} (generic) +@code{ensure-metaclass} (procedure) -The applied method should compute and return the slots (union of direct -and inherited) for @var{class} as a list of slot definitions. When -@code{compute-slots} is called, all the @var{class} metaobject slots -mentioned for @code{compute-cpl} have been initialized, plus the -following: @code{cpl}, @code{redefined} (@code{#f}), @code{environment}. -The value returned by @code{compute-slots} will be stored in the -@code{slots} slot. +@item +@code{make @var{metaclass} @dots{}} (generic) +@itemize @bullet @item -@code{compute-get-n-set @var{class} @var{slot-def}} (generic) +@code{allocate-instance} (generic) -@code{initialize} calls @code{compute-get-n-set} for each slot computed -by @code{compute-slots}. The applied method should compute and return a -pair of closures that, respectively, get and set the value of the specified -slot. The get closure should have arity 1 and expect a single argument -that is the instance whose slot value is to be retrieved. The set closure -should have arity 2 and expect two arguments, where the first argument is -the instance whose slot value is to be set and the second argument is the -new value for that slot. The closures should be returned in a two element -list: @code{(list @var{get} @var{set})}. +@item +@code{initialize} (generic) -The closures returned by @code{compute-get-n-set} are stored as part of -the value of the @var{class} metaobject's @code{getters-n-setters} slot. -Specifically, the value of this slot is a list with the same number of -elements as there are slots in the class, and each element looks either like +@itemize @bullet +@item +@code{compute-cpl} (generic) -@example -@code{(@var{slot-name-symbol} @var{init-function} . @var{index})} -@end example +@itemize @bullet +@item +@code{compute-std-cpl} (procedure) +@end itemize -or like +@item +@code{compute-slots} (generic) -@example -@code{(@var{slot-name-symbol} @var{init-function} @var{get} @var{set})} -@end example +@item +@code{compute-get-n-set} (generic) -Where the get and set closures are replaced by @var{index}, the slot is -an instance slot and @var{index} is the slot's index in the underlying -structure: GOOPS knows how to get and set the value of such slots and so -does not need specially constructed get and set closures. Otherwise, -@var{get} and @var{set} are the closures returned by @code{compute-get-n-set}. +@item +@code{compute-getter-method} (generic) -The structure of the @code{getters-n-setters} slot value is important when -understanding the next customizable generic functions that @code{initialize} -calls@dots{} +@item +@code{compute-setter-method} (generic) +@end itemize +@end itemize +@end itemize +@end itemize @item -@code{compute-getter-method @var{class} @var{gns}} (generic) +@code{class-redefinition} (generic) -@code{initialize} calls @code{compute-getter-method} for each of the class's -slots (as determined by @code{compute-slots}) that includes a -@code{#:getter} or @code{#:accessor} slot option. @var{gns} is the -element of the @var{class} metaobject's @code{getters-n-setters} slot that -specifies how the slot in question is referenced and set, as described -above under @code{compute-get-n-set}. The applied method should create -and return a method that is specialized for instances of type @var{class} -and uses the get closure to retrieve the slot's value. [ *fixme Need -to insert something here about checking that the value is not unbound. ] -@code{initialize} uses @code{add-method!} to add the returned method to -the generic function named by the slot definition's @code{#:getter} or -@code{#:accessor} option. +@itemize @bullet +@item +@code{remove-class-accessors} (generic) @item -@code{compute-setter-method @var{class} @var{gns}} (generic) +@code{update-direct-method!} (generic) -@code{compute-setter-method} is invoked with the same arguments as -@code{compute-getter-method}, for each of the class's slots that includes -a @code{#:setter} or @code{#:accessor} slot option. The applied method -should create and return a method that is specialized for instances of -type @var{class} and uses the set closure to set the slot's value. -@code{initialize} then uses @code{add-method!} to add the returned method -to the generic function named by the slot definition's @code{#:setter} -or @code{#:accessor} option. +@item +@code{update-direct-subclass!} (generic) @end itemize +@end itemize + +Wherever a step above is marked as ``generic'', it can be customized, +and the detail shown below it is only ``correct'' insofar as it +describes what the default method of that generic function does. For +example, if you write an @code{initialize} method, for some metaclass, +that does not call @code{next-method} and does not call +@code{compute-cpl}, then @code{compute-cpl} will not be called when a +class is defined with that metaclass. -@code{define-class} expands to an expression which +A @code{(define-class ...)} form (@pxref{Class Definition}) expands to +an expression which @itemize @bullet @item @@ -2264,8 +2219,7 @@ checks that it is being evaluated only at top level defines any accessors that are implied by the @var{slot-definition}s @item -uses @code{class} to create the new class (@pxref{Class Definition -Internals,, class}) +uses @code{class} to create the new class @item checks for a previous class definition for @var{name} and, if found, @@ -2316,8 +2270,7 @@ class precedence list defaults the @code{#:environment}, @code{#:name} and @code{#:metaclass} options, if they are not specified by @var{options}, to the current top-level environment, the unbound value, and @code{(ensure-metaclass -@var{supers})} respectively (@pxref{Class Definition Internals,, -ensure-metaclass}) +@var{supers})} respectively @item checks for duplicate classes in @var{supers} and duplicate slot names in @@ -2353,55 +2306,113 @@ has to be created once. The @code{env} parameter is ignored. @end deffn -@deffn procedure ensure-metaclass-with-supers meta-supers -@code{ensure-metaclass-with-supers} is an internal procedure used by -@code{ensure-metaclass} (@pxref{Class Definition Internals,, -ensure-metaclass}). It returns a metaclass that is the union by -inheritance of the metaclasses in @var{meta-supers}. +@deffn generic make metaclass @dots{} +@var{metaclass} is the metaclass of the class being defined, either +taken from the @code{#:metaclass} class option or computed by +@code{ensure-metaclass}. The applied method must create and return the +fully initialized class metaobject for the new class definition. @end deffn -The internals of @code{make}, which is ultimately used to create the new -class object, are described in @ref{Customizing Instance Creation}, -which covers the creation and initialization of instances in general. +The @code{(make @var{metaclass} @dots{})} invocation is a particular +case of the instance creation protocol covered in the previous section. +It will create an class metaobject with metaclass @var{metaclass}. By +default, this metaobject will be initialized by the @code{initialize} +method that is specialized for instances of type @code{<class>}. -@node Customizing Class Definition -@subsection 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 +The @code{initialize} method for classes (signature @code{(initialize +<class> initargs)}) calls the following generic functions. @itemize @bullet @item -(initialize @var{class} @dots{}) -@end itemize +@code{compute-cpl @var{class}} (generic) -where @var{class} is the newly allocated class instance, and the default -@code{initialize} method for arguments of type @code{<class>} calls the -generic functions +The applied method should compute and return the class precedence list +for @var{class} as a list of class metaobjects. When @code{compute-cpl} +is called, the following @var{class} metaobject slots have all been +initialized: @code{name}, @code{direct-supers}, @code{direct-slots}, +@code{direct-subclasses} (empty), @code{direct-methods}. The value +returned by @code{compute-cpl} will be stored in the @code{cpl} slot. -@itemize @bullet @item -(compute-cpl @var{class}) +@code{compute-slots @var{class}} (generic) -@item -(compute-slots @var{class}) +The applied method should compute and return the slots (union of direct +and inherited) for @var{class} as a list of slot definitions. When +@code{compute-slots} is called, all the @var{class} metaobject slots +mentioned for @code{compute-cpl} have been initialized, plus the +following: @code{cpl}, @code{redefined} (@code{#f}), @code{environment}. +The value returned by @code{compute-slots} will be stored in the +@code{slots} slot. @item -(compute-get-n-set @var{class} @var{slot-def}), for each of the slot -definitions returned by @code{compute-slots} +@code{compute-get-n-set @var{class} @var{slot-def}} (generic) + +@code{initialize} calls @code{compute-get-n-set} for each slot computed +by @code{compute-slots}. The applied method should compute and return a +pair of closures that, respectively, get and set the value of the specified +slot. The get closure should have arity 1 and expect a single argument +that is the instance whose slot value is to be retrieved. The set closure +should have arity 2 and expect two arguments, where the first argument is +the instance whose slot value is to be set and the second argument is the +new value for that slot. The closures should be returned in a two element +list: @code{(list @var{get} @var{set})}. + +The closures returned by @code{compute-get-n-set} are stored as part of +the value of the @var{class} metaobject's @code{getters-n-setters} slot. +Specifically, the value of this slot is a list with the same number of +elements as there are slots in the class, and each element looks either like + +@example +@code{(@var{slot-name-symbol} @var{init-function} . @var{index})} +@end example + +or like + +@example +@code{(@var{slot-name-symbol} @var{init-function} @var{get} @var{set})} +@end example + +Where the get and set closures are replaced by @var{index}, the slot is +an instance slot and @var{index} is the slot's index in the underlying +structure: GOOPS knows how to get and set the value of such slots and so +does not need specially constructed get and set closures. Otherwise, +@var{get} and @var{set} are the closures returned by @code{compute-get-n-set}. + +The structure of the @code{getters-n-setters} slot value is important when +understanding the next customizable generic functions that @code{initialize} +calls@dots{} @item -(compute-getter-method @var{class} @var{slot-def}), for each of the -slot definitions returned by @code{compute-slots} that includes a -@code{#:getter} or @code{#:accessor} slot option +@code{compute-getter-method @var{class} @var{gns}} (generic) + +@code{initialize} calls @code{compute-getter-method} for each of the +class's slots (as determined by @code{compute-slots}) that includes a +@code{#:getter} or @code{#:accessor} slot option. @var{gns} is the +element of the @var{class} metaobject's @code{getters-n-setters} slot +that specifies how the slot in question is referenced and set, as +described above under @code{compute-get-n-set}. The applied method +should create and return a method that is specialized for instances of +type @var{class} and uses the get closure to retrieve the slot's value. +@code{initialize} uses @code{add-method!} to add the returned method to +the generic function named by the slot definition's @code{#:getter} or +@code{#:accessor} option. @item -(compute-setter-method @var{class} @var{slot-def}), for each of the -slot definitions returned by @code{compute-slots} that includes a -@code{#:setter} or @code{#:accessor} slot option. +@code{compute-setter-method @var{class} @var{gns}} (generic) + +@code{compute-setter-method} is invoked with the same arguments as +@code{compute-getter-method}, for each of the class's slots that includes +a @code{#:setter} or @code{#:accessor} slot option. The applied method +should create and return a method that is specialized for instances of +type @var{class} and uses the set closure to set the slot's value. +@code{initialize} then uses @code{add-method!} to add the returned method +to the generic function named by the slot definition's @code{#:setter} +or @code{#:accessor} option. @end itemize +@node Customizing Class Definition +@subsection Customizing Class Definition + If the metaclass of the new class is something more specialized than the default @code{<class>}, then the type of @var{class} in the calls above is more specialized than @code{<class>}, and hence it becomes possible @@ -2419,8 +2430,7 @@ customized in order to modify the CPL ordering algorithm for all classes with a special metaclass. The default CPL algorithm is encapsulated by the @code{compute-std-cpl} -procedure, which is in turn called by the default @code{compute-cpl} -method. +procedure, which is called by the default @code{compute-cpl} method. @deffn procedure compute-std-cpl class Compute and return the class precedence list for @var{class} according @@ -2489,7 +2499,7 @@ allocation to do this. @end example The usage of @code{compute-getter-method} and @code{compute-setter-method} -is described in @ref{MOP Specification}. +is described in @ref{Class Definition Protocol}. @code{compute-cpl} and @code{compute-get-n-set} are called by the standard @code{initialize} method for classes whose metaclass is @@ -2500,152 +2510,6 @@ 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 Customizing Instance Creation -@subsection Customizing Instance Creation - -@code{make <class> . @var{initargs}} (method) - -@itemize @bullet -@item -@code{allocate-instance @var{class} @var{initargs}} (generic) - -The applied @code{allocate-instance} method should allocate storage for -a new instance of class @var{class} and return the uninitialized instance. - -@item -@code{initialize @var{instance} @var{initargs}} (generic) - -@var{instance} is the uninitialized instance returned by -@code{allocate-instance}. The applied method should initialize the new -instance in whatever sense is appropriate for its class. The method's -return value is ignored. -@end itemize - -@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{<class>}, by -defining a @code{make} method that is specialized to that metaclass. - -Normally, however, the method for classes with metaclass @code{<class>} -will be applied. This method calls two generic functions: - -@itemize @bullet -@item -(allocate-instance @var{class} . @var{initargs}) - -@item -(initialize @var{instance} . @var{initargs}) -@end itemize - -@code{allocate-instance} allocates storage for and returns the new -instance, uninitialized. You might customize @code{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 @code{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 @code{make} and -@code{initialize}, so that GOOPS knows how to make classes from the -other system, access instance slots, and so on. - -@code{initialize} initializes the instance that is returned by -@code{allocate-instance}. The standard GOOPS methods perform -initializations appropriate to the instance class. - -@itemize @bullet -@item -At the least specialized level, the method for instances of type -@code{<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 @var{initargs}. - -@item -The method for instances of type @code{<class>} calls -@code{(next-method)}, then performs the class initializations described -in @ref{Customizing Class Definition}. - -@item -and so on for generic functions, method, operator classes @dots{} -@end itemize - -Similarly, you can customize the initialization of instances of any -application-defined class by defining an @code{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 @code{#:init-thunk} keywords -and closures in the slot definitions, it is neater to write an -@code{initialize} method for the class that queries the database once -and initializes all the dependent slot values according to the results. - -@node Class Redefinition -@subsection Class Redefinition - -The default @code{class-redefinition} method, specialized for classes -with the default metaclass @code{<class>}, has the following internal -protocol. - -@code{class-redefinition (@var{old <class>}) (@var{new <class>})} -(method) - -@itemize @bullet -@item -@code{remove-class-accessors! @var{old}} (generic) - -@item -@code{update-direct-method! @var{method} @var{old} @var{new}} (generic) - -@item -@code{update-direct-subclass! @var{subclass} @var{old} @var{new}} (generic) -@end itemize - -This protocol cleans up things that the definition of the old class -once changed and modifies things to work with the new class. - -The default @code{remove-class-accessors!} method removes the -accessor methods of the old class from all classes which they -specialize. - -The default @code{update-direct-method!} method substitutes the new -class for the old in all methods specialized to the old class. - -The default @code{update-direct-subclass!} method invokes -@code{class-redefinition} recursively to handle the redefinition of -subclasses. - -When a class is redefined, any existing instance of the redefined class -will be modified for the new class definition before the next time that -any of the instance's slot is referenced or set. GOOPS modifies each -instance by calling the generic function @code{change-class}. - -The default @code{change-class} method copies slot values from the old -to the modified instance, and initializes new slots, as described in -@ref{Changing the Class of an Instance}. After doing so, it makes a -generic function invocation that can be used to customize the instance -update algorithm. - -@code{change-class (@var{old-instance <object>}) (@var{new <class>})} (method) - -@itemize @bullet -@item -@code{update-instance-for-different-class @var{old-instance} @var{new-instance}} (generic) - -@code{change-class} invokes @code{update-instance-for-different-class} -as the last thing that it does before returning. The applied method can -make any further adjustments to @var{new-instance} that are required to -complete or modify the change of class. The return value from the -applied method is ignored. - -The default @code{update-instance-for-different-class} method does -nothing. -@end itemize @node Method Definition @subsection Method Definition @@ -2655,7 +2519,9 @@ nothing. @itemize @bullet @item @code{add-method! @var{target} @var{method}} (generic) +@end itemize +@noindent @code{define-method} invokes the @code{add-method!} generic function to handle adding the new method to a variety of possible targets. GOOPS includes methods to handle @var{target} as @@ -2673,12 +2539,12 @@ a primitive generic (@pxref{Extending Primitives}) By defining further methods for @code{add-method!}, you can theoretically handle adding methods to further types of target. -@end itemize + @node Method Definition Internals @subsection Method Definition Internals -@code{define-method} +@code{define-method}: @itemize @bullet @item @@ -2708,7 +2574,8 @@ The @var{parameter} and @var{body} parameters should be as for define-method}). @end deffn -@code{method} +@noindent +@code{method}: @itemize @bullet @item @@ -2734,6 +2601,7 @@ parameter combinations to which this method will be applicable. function parameters when this method is invoked. @end deffn +@noindent @code{make-method} is a simple wrapper around @code{make} with metaclass @code{<method>}. @@ -2834,71 +2702,47 @@ accessor, passing the setter generic function as the value of the @node Generic Function Invocation @subsection Generic Function Invocation -[ *fixme* Description required here. ] +There is a detailed and customizable protocol involved in the process of +invoking a generic function --- i.e., in the process of deciding which +of the generic function's methods are applicable to the current +arguments, and which one of those to apply. Here is a summary diagram +of the generic functions involved. -@code{apply-generic} +@noindent +@code{apply-generic} (generic) @itemize @bullet @item -@code{no-method} +@code{no-method} (generic) @item -@code{compute-applicable-methods} +@code{compute-applicable-methods} (generic) @item -@code{sort-applicable-methods} - -@item -@code{apply-methods} +@code{sort-applicable-methods} (generic) +@itemize @bullet @item -@code{no-applicable-method} +@code{method-more-specific?} (generic) @end itemize -@code{sort-applicable-methods} +@item +@code{apply-methods} (generic) @itemize @bullet @item -@code{method-more-specific?} -@end itemize +@code{apply-method} (generic) -@code{apply-methods} - -@itemize @bullet @item -@code{apply-method} +@code{no-next-method} (generic) @end itemize -@code{next-method} - -@itemize @bullet @item -@code{no-next-method} +@code{no-applicable-method} @end itemize - -@node Class Options -@section Class Options - -@deffn {class option} #:metaclass metaclass -The @code{#:metaclass} class option specifies the metaclass of the class -being defined. @var{metaclass} must be a class that inherits from -@code{<class>}. For the use of metaclasses, see @ref{Metaobjects and -the Metaobject Protocol} and @ref{Terminology}. - -If the @code{#:metaclass} option is absent, GOOPS reuses or constructs a -metaclass for the new class by calling @code{ensure-metaclass} -(@pxref{Class Definition Internals,, ensure-metaclass}). -@end deffn - -@deffn {class option} #:name name -The @code{#: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 @code{#:name} option is absent, GOOPS uses the first argument to -@code{define-class} as the class name. -@end deffn +We do not yet have full documentation for these. Please refer to the +code (@file{oop/goops.scm}) for details. @node Redefining a Class @@ -2972,8 +2816,8 @@ be customized@dots{} @node Customizing Class Redefinition @subsection Customizing Class Redefinition -When @code{define-class} notices that a class is being redefined, -it constructs the new class metaobject as usual, and then invokes the +When @code{define-class} notices that a class is being redefined, it +constructs the new class metaobject as usual, then invokes the @code{class-redefinition} generic function with the old and new classes as arguments. Therefore, if the old or new classes have metaclasses other than the default @code{<class>}, class redefinition behaviour can @@ -2992,6 +2836,26 @@ Implements GOOPS' default class redefinition behaviour, as described in for the new class definition. @end deffn +The default @code{class-redefinition} method, for classes with the +default metaclass @code{<class>}, calls the following generic functions, +which could of course be individually customized. + +@deffn generic remove-class-accessors! old +The default @code{remove-class-accessors!} method removes the accessor +methods of the old class from all classes which they specialize. +@end deffn + +@deffn generic update-direct-method! method old new +The default @code{update-direct-method!} method substitutes the new +class for the old in all methods specialized to the old class. +@end deffn + +@deffn generic update-direct-subclass! subclass old new +The default @code{update-direct-subclass!} method invokes +@code{class-redefinition} recursively to handle the redefinition of +subclasses. +@end deffn + An alternative class redefinition strategy could be to leave all existing instances as instances of the old class, but accepting that the old class is now ``nameless'', since its name has been taken over by the @@ -3015,34 +2879,18 @@ is specialized for this metaclass: When customization can be as easy as this, aren't you glad that GOOPS implements the far more difficult strategy as its default! -Finally, note that, if @code{class-redefinition} itself is not customized, -the default @code{class-redefinition} method invokes three further -generic functions that could be individually customized: - -@itemize @bullet -@item -(remove-class-accessors! @var{old-class}) - -@item -(update-direct-method! @var{method} @var{old-class} @var{new-class}) - -@item -(update-direct-subclass! @var{subclass} @var{old-class} @var{new-class}) -@end itemize - -and the default methods for these generic functions invoke further -generic functions, and so on@dots{} The detailed protocol for all of these -is described in @ref{MOP Specification}. @node Changing the Class of an Instance @section Changing the Class of an Instance -You can change the class of an existing instance by invoking the -generic function @code{change-class} with two arguments: the instance -and the new class. +When a class is redefined, any existing instance of the redefined class +will be modified for the new class definition before the next time that +any of the instance's slots is referenced or set. GOOPS modifies each +instance by calling the generic function @code{change-class}. -@deffn generic change-class -@end deffn +More generally, you can change the class of an existing instance at any +time by invoking the generic function @code{change-class} with two +arguments: the instance and the new class. The default method for @code{change-class} decides how to implement the change of class by looking at the slot definitions for the instance's @@ -3053,6 +2901,9 @@ discarded. Slots that are present only in the new class are initialized using the corresponding slot definition's init function (@pxref{Classes,, slot-init-function}). +@deffn generic change-class instance new-class +@end deffn + @deffn {method} change-class (obj <object>) (new <class>) Modify instance @var{obj} to make it an instance of class @var{new}. @@ -3064,11 +2915,20 @@ pre-existing slots are initialized according to @var{new}'s slot definitions' init functions. @end deffn +The default @code{change-class} method also invokes another generic +function, @code{update-instance-for-different-class}, as the last thing +that it does before returning. The applied +@code{update-instance-for-different-class} method can make any further +adjustments to @var{new-instance} that are required to complete or +modify the change of class. The return value from the applied method is +ignored. + +@deffn generic update-instance-for-different-class old-instance new-instance +A generic function that can be customized to put finishing touches to an +instance whose class has just been changed. The default +@code{update-instance-for-different-class} method does nothing. +@end deffn + Customized change of class behaviour can be implemented by defining @code{change-class} methods that are specialized either by the class of the instances to be modified or by the metaclass of the new class. - -When a class is redefined (@pxref{Redefining a Class}), and the default -class redefinition behaviour is not overridden, GOOPS (eventually) -invokes the @code{change-class} generic function for each existing -instance of the redefined class. |