Generic functions and methods

Neither STKLOS nor CLOS use the message mechanism for methods as most Object Oriented language do. Instead, they use the notion of generic function. A generic function can be seen as a methods ``tanker''. When the evaluator requestd 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 funtion must be ``called'' the system will

  1. search among all the generic function those which are applicable
  2. sort the list of applicable methods in the ``most specific'' order
  3. call the most specific method of this list (i.e. the first method of the sorted methods list).

The definition of a generic function is done with the ndexfile(index-entry "define-generic" "tt" aux )define-generic macro. Definition of a new method is done with the ndexfile(index-entry "define-method" "tt" aux )define-method macro. Note that ndexfile(index-entry "define-method" "tt" aux )define-method automatically defines the generic function if it has not been defined before. Consequently, most of the time, the ndexfile(index-entry "define-generic" "tt" aux )define-generic needs not be used.

Consider the following definitions: $\Longrightarrow$
$\Longrightarrow$ unspecified error makeotherˆ`=̀13`


          gobblecr(define-generic M)(define-method M((a <integer>) b) 'integer)(define-method M((a <real>) b) 'real)(define-method M(a b) 'top)

The ndexfile(index-entry "define-generic" "tt" aux )define-generic call defines M 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 M 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 speciliazer is given, the system defaults it to ndexfile(index-entry "<top>" "tt" aux )<top>. Thus, the first method definition is equivalent to

$\Longrightarrow$
$\Longrightarrow$ unspecified error makeotherˆ`=̀13`


          gobblecr(define-method M((a <integer>) (b <top>)) 'integer)

Now, let us look at some possible calls to generic function M: $\Longrightarrow$
$\Longrightarrow$ unspecified error makeotherˆ`=̀13`


          gobblecr(M 2 3) integer(M 2 #t) integer(M 1.2 'a) real(M #3 'a) real(M #t #f) top(M 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 $\Longrightarrow$
$\Longrightarrow$ unspecified error makeotherˆ`=̀13`


          gobblecr(define-method M ((a <integer>) (b <number>)) 'integer-number)(define-method M ((a <integer>) (b <real>))   'integer-real)(define-method M (a (b <number>)) 'top-number)

In this case, $\Longrightarrow$
$\Longrightarrow$ unspecified error makeotherˆ`=̀13`


          gobblecr(M 1 2) integer-integer(M 1 1.0) integer-real(M 1 #t) integer(M 'a 1) 'top-number