Re: how to make a "cacheing" slot
Brian Denheyer writes:
>
> Here's the situation :
>
> (define-class <foo> ()
> ((descriptive-value)
> (calc-value)))
>
> descriptive-value is a value which is meaningful to the user such as
> %. calc-value is a value used internally which is calculated from
> descriptive-value. It only needs to be recalculated when
> descriptive-value changes.
>
> My first thought was to make descriptive-value a virtual slot with a
> setter which will update calc-value. Since there is an actual value
> associated with descriptive-value it doesn't make sense to do this.
>
You can use an active-slot to do what you want. Active slots are
allocated but you can place a handler before/after each slot
read/write (see the file STklos/active-slot.stklos). The before
handlers can even be used as controllers. For instance, if the before
slot-set! handler return #f the slot value is not changed
To answer your problem, you can define the following class, where the
calc-value slot is always the square of the user-value slot:
(define-class <foo> ()
((user-value :allocation :active
:accessor user-value
:init-keyword :user-value
:after-slot-set! (lambda (o v)
(display "Recomputing calc-value \n")
(slot-set! o 'calc-value (* v v))))
(calc-value))
:metaclass <Active-metaclass>)
And an example of usage:
STk> (define o (make <foo> :user-value 10))
Recomputing calc-value
o
STk> (describe o)
#[<foo> 402173a8] is an an instance of class <foo>.
Slots are:
user-value = 10
calc-value = 100
STk> (set! (user-value o) 3)
Recomputing calc-value
STk> (describe o)
#[<foo> 402173a8] is an an instance of class <foo>.
Slots are:
user-value = 3
calc-value = 9
>
> P.S. For a 100pt bonus, what's a good way to do this if "cache-value"
> depends on more than 1 slot...
This scheme scales to any number of slots, the only problem is that
the after-slot-set! fuction are more difficult to write: The following
class has a slot a+b which is always the sum of the slots a and
b. Note that here we have to take into account that a slot can be
unbound when we compute the other.
(define-class <bar> ()
((a :allocation :active
:init-keyword :a
:init-form 0
:after-slot-set! (lambda (o v)
(let ((other (if (slot-bound? o 'b)
(slot-ref o 'b)
0)))
(slot-set! o 'a+b (+ v other)))))
(b :allocation :active
:init-keyword :b
:init-form 0
:after-slot-set! (lambda (o v)
(let ((other (if (slot-bound? o 'a)
(slot-ref o 'a)
0)))
(slot-set! o 'a+b (+ v other)))))
(a+b))
:metaclass <Active-metaclass>)
Hope it helps
-- Erick
Received on Tue Nov 30 1999 - 14:55:14 CET
This archive was generated by hypermail 2.3.0
: Mon Jul 21 2014 - 19:38:59 CEST