Node:Slot description, Next:, Previous:Instance creation and slot access, Up:Inheritance



5.4.3 Slot description

When specifying a slot, a set of options can be given to the system. Each option is specified with a keyword. The list of authorized keywords is given below:

To illustrate slot description, we shall redefine the <complex> class seen before. A definition could be:

(define-class <complex> (<number>)
   (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))

With this definition, the r and i slot are set to 0 by default. Value of a slot can also be specified by calling make with the #:r and #:i keywords. Furthermore, the generic functions get-r and set-r! (resp. get-i and set-i!) are automatically defined by the system to read and write the r (resp. i) slot.

(define c1 (make <complex> #:r 1 #:i 2))
(get-r c1) => 1
(set-r! c1 12)
(get-r c1) => 12
(define c2 (make <complex> #:r 2))
(get-r c2) => 2
(get-i c2) => 0

Accessors provide an uniform access for reading and writing an object slot. Writing a slot is done with an extended form of set! which is close to the Common Lisp setf macro. So, another definition of the previous <complex> class, using the #:accessor option, could be:

(define-class <complex> (<number>)
   (r #:init-value 0 #:accessor real-part #:init-keyword #:r)
   (i #:init-value 0 #:accessor imag-part #:init-keyword #:i))

Using this class definition, reading the real part of the c complex can be done with:

(real-part c)
and setting it to the value contained in the new-value variable can be done using the extended form of set!.
(set! (real-part c) new-value)

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 <complex> class using virtual slots is given in Figure 2.


(define-class <complex> (<number>)
   ;; 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)))))))

Fig 2: A <complex> number class definition using virtual slots



This class definition implements two real slots (r and i). Values of the m and a virtual slots are calculated from real slot values. Reading a virtual slot leads to the application of the function defined in the #:slot-ref option. Writing such a slot leads to the application of the function defined in the #:slot-set! option. For instance, the following expression

(slot-set! c 'a 3)

permits to set the angle of the c complex number. This expression conducts, in fact, to the evaluation of the following expression

((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)

A more complete example is given below:


(define c (make <complex> #:r 12 #:i 20))
(real-part c) => 12
(angle c) => 1.03037682652431
(slot-set! c 'i 10)
(set! (real-part c) 1)
(describe c) =>
          #<<complex> 401e9b58> is an instance of class <complex>
          Slots are:
               r = 1
               i = 10
               m = 10.0498756211209
               a = 1.47112767430373

Since initialization keywords have been defined for the four slots, we can now define the make-rectangular and make-polar standard Scheme primitives.

(define make-rectangular
   (lambda (x y) (make <complex> #:r x #:i y)))

(define make-polar
   (lambda (x y) (make <complex> #:magn x #:angle y)))