(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