DOC HOME SITE MAP MAN PAGES GNU INFO SEARCH PRINT BOOK
 

(goops.info.gz) Slot description

Info Catalog (goops.info.gz) Instance creation and slot access (goops.info.gz) Inheritance (goops.info.gz) Class precedence list
 
 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:
 
    * `#:init-value' permits to supply a default value for the slot. This
      default value is obtained by evaluating the form given after the
      `#:init-form' in the global environment, at class definition time.
 
    * `#:init-thunk' permits to supply a thunk that will provide a
      default value for the slot. The value is obtained by evaluating the
      thunk a instance creation time.
 
    * `#:init-keyword' permits to specify the keyword for initializing a
      slot. The init-keyword may be provided during instance creation
      (i.e. in the `make' optional parameter list). Specifying such a
      keyword during instance initialization will supersede the default
      slot initialization possibly given with `#:init-form'.
 
    * `#:getter' permits to supply the name for the slot getter. The
      name binding is done in the environment of the `define-class'
      macro.
 
    * `#:setter' permits to supply the name for the slot setter. The
      name binding is done in the environment of the `define-class'
      macro.
 
    * `#:accessor' permits to supply the name for the slot accessor. The
      name binding is done in the global environment. An accessor
      permits to get and set the value of a slot. Setting the value of a
      slot is done with the extended version of `set!'.
 
    * `#:allocation' permits to specify how storage for the slot is
      allocated. Three kinds of allocation are provided.  They are
      described below:
 
         - `#:instance' indicates that each instance gets its own
           storage for the slot. This is the default.
 
         - `#:class' indicates that there is one storage location used
           by all the direct and indirect instances of the class. This
           permits to define a kind of global variable which can be
           accessed only by (in)direct instances of the class which
           defines this slot.
 
         - `#:each-subclass' indicates that there is one storage
           location used by all the direct instances of the class. In
           other words, if two classes are not siblings in the class
           hierarchy, they will not see the same value.
 
         - `#:virtual' indicates that no storage will be allocated for
           this slot.  It is up to the user to define a getter and a
           setter function for this slot. Those functions must be
           defined with the `#:slot-ref' and `#:slot-set!' options. See
           the example 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)))
 
Info Catalog (goops.info.gz) Instance creation and slot access (goops.info.gz) Inheritance (goops.info.gz) Class precedence list
automatically generated byinfo2html