Provides a metaclass to add
:propagated slot allocation option.
When a slot allocation has
to the slot is redirected to other object’s slot.
It is handy for composite objects to keep external
interface simple, for access to the slot of inner objects
can be disguised as if it is a slot of the parent object.
An example would work better than explanation.
Suppose you have a
<rect> class to represent
generic rectangular area, and you want to use it when you create
<viewport> class by composition, instead of
inheritance. A simple way would be as follows:
(define-class <rect> () ((width :init-keyword :width) (height :init-keyword :height))) (define-class <viewport> () ((dimension :init-form (make <rect>)) ;; ... other slots ... ))
With this definition, whenever you want to access the viewport’s
width or height, you have to go through
<rect> object, e.g.
(~ viewport'dimension'width). This is not only cumbersome,
but the users of viewport class have to know that how the
viewport is composed (it’s not necessarily a bad thing,
but sometimes you may want to hide it).
gauche.mop.propagate, you can define slots
that are proxies of
(use gauche.mop.propagate) (define-class <rect> () ((width :init-keyword :width) (height :init-keyword :height))) (define-class <viewport> (<propagate-mixin>) ((dimension :init-form (make <rect>)) (width :allocation :propagated :propagate 'dimension :init-keyword :width) (height :allocation :propagated :propagate 'dimension :init-keyword :height)))
:propagated allocation, the slots are not actually
<viewport> instance, and accesses to the
slots are redirected to the object in the slot specified by
:propagate slot option—in this case, the
It is somewhat similar to the virtual slots, but it’s more convenient
for you don’t explicitly write procedures to redirect the access.
Now you can treat
height as if they
are slots of
<viewport>. You can even make them
init-keyword (but you can’t use
:init-value; if you want to specify
default values, give the default values to the actual object).
gosh> (define vp (make <viewport> :width 640 :height 480)) vp gosh> (d vp) #<<viewport> 0xc5a1e0> is an instance of class <viewport> slots: dimension : #<<rect> 0xc5a130> width : 640 height : 480 gosh> (set! (~ vp'width) 800) #<undef> gosh> (~ vp'width) 800
Here’s two classes that enables this feature.
Usually all you have to do is to inherit
:propagated slot allocation.
The propagated slot has to have
:propagate slot option
which specifies the name of the slot that points to an object
that actually holds the value of the slot.
If a slot has
:propagated slot allocation but
does not have
:propagate slot option, an error is signaled.
:propagate slot option should have a value
of either a symbol, or a list of two symbols.
If it is a symbol, it names the slot that contains an object, whose slot with the same name of the propagate slot holds the value.
If it is a list of two symbols as
(X Y), then
the access to this propagated slot actually works as
(slot-ref (slot-ref obj X) Y).
If you want to make a propagated slot initializable by init-keywords, make sure the slot holding the actual object comes before the propagated slots. Slot initialization proceeds in the order of appearance by default, and you want the actual object is created before setting values.
This is a convenience mixin class. Instead of giving
:metaclass <propagate-meta>, you can just inherit
this calss to make propagated slots available.