Node:Generic functions and methods, Next:Next-method, Previous:Generic functions, Up:Generic functions
Neither GOOPS nor CLOS use the message mechanism for methods as most Object Oriented language do. Instead, they use the notion of 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 M is more specific than a method M' if the class of its parameters are more specific than the M' ones. To be more precise, when a generic function must be "called" the system will:
The definition of a generic function is done with the
define-generic
macro. Definition of a new method is done with the
define-method
macro. Note that define-method
automatically
defines the generic function if it has not been defined
before. Consequently, most of the time, the define-generic
needs
not be used.
Consider the following definitions:
(define-generic G) (define-method (G (a <integer>) b) 'integer) (define-method (G (a <real>) b) 'real) (define-method (G a b) 'top)
The define-generic
call defines 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 G generic
function. Each method uses a sequence of 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 <top>
. Thus, the first method definition is
equivalent to
(define-method (G (a <integer>) (b <top>)) 'integer)
Now, let us look at some possible calls to generic function G:
(G 2 3) => integer (G 2 #t) => integer (G 1.2 'a) => real (G #t #f) => top (G 1 2 3) => error (since no method exists for 3 parameters)
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
(define-method (G (a <integer>) (b <number>)) 'integer-number) (define-method (G (a <integer>) (b <real>)) 'integer-real) (define-method (G (a <integer>) (b <integer>)) 'integer-integer) (define-method (G a (b <number>)) 'top-number)
In this case,
(G 1 2) => integer-integer (G 1 1.0) => integer-real (G 1 #t) => integer (G 'a 1) => top-number