Next: Handling Invocation Errors, Previous: Next-method, Up: Methods and Generic Functions [Contents][Index]
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.
The three next lines define methods for G.  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’s look at some possible calls to the 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 methods above use only one specializer per parameter list. But in general, any or all of a method’s parameters may be specialized. Suppose we define 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)
With these definitions:
(G 1 2) ⇒ integer-integer (G 1 1.0) ⇒ integer-real (G 1 #t) ⇒ integer (G 'a 1) ⇒ top-number
As a further example we shall continue to define operations on the
<my-complex> class.  Suppose that we want to use it to implement
complex numbers completely.  For instance a definition for the addition
of two complex numbers could be
(define-method (new-+ (a <my-complex>) (b <my-complex>))
  (make-rectangular (+ (real-part a) (real-part b))
                    (+ (imag-part a) (imag-part b))))
To be sure that the + used in the method new-+ is the
standard addition we can do:
(define-generic new-+)
(let ((+ +))
  (define-method (new-+ (a <my-complex>) (b <my-complex>))
    (make-rectangular (+ (real-part a) (real-part b))
                      (+ (imag-part a) (imag-part b)))))
The define-generic ensures here that new-+ will be defined
in the global environment. Once this is done, we can add methods to the
generic function new-+ which make a closure on the +
symbol.  A complete writing of the new-+ methods is shown in
Figure 8.1.
(define-generic new-+)
(let ((+ +))
  (define-method (new-+ (a <real>) (b <real>)) (+ a b))
  (define-method (new-+ (a <real>) (b <my-complex>)) 
    (make-rectangular (+ a (real-part b)) (imag-part b)))
  (define-method (new-+ (a <my-complex>) (b <real>))
    (make-rectangular (+ (real-part a) b) (imag-part a)))
  (define-method (new-+ (a <my-complex>) (b <my-complex>))
    (make-rectangular (+ (real-part a) (real-part b))
                      (+ (imag-part a) (imag-part b))))
  (define-method (new-+ (a <number>))  a)
  
  (define-method (new-+) 0)
  (define-method (new-+ . args)
    (new-+ (car args) 
      (apply new-+ (cdr args)))))
(set! + new-+)
Figure 8.1: Extending + to handle complex numbers
We take advantage here of the fact that generic function are not obliged
to have a fixed number of parameters.  The four first methods implement
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 (as is also true for the
primitive +).  The last method takes an arbitrary number of
parameters33.  This method acts as a kind of reduce: it calls the
dyadic addition on the car of the list and on the result of
applying it on its rest.  To finish, the set! permits to redefine
the + symbol to our extended addition.
To conclude our implementation (integration?) of complex numbers, we could redefine standard Scheme predicates in the following manner:
(define-method (complex? c <my-complex>) #t) (define-method (complex? c) #f) (define-method (number? n <number>) #t) (define-method (number? n) #f) …
Standard primitives in which complex numbers are involved could also be redefined in the same manner.
The parameter list for a 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
Next: Handling Invocation Errors, Previous: Next-method, Up: Methods and Generic Functions [Contents][Index]