Is there a way to have a method triggered automatically whenever a
class slot is modified?
I have two slots which must maintain a certain relation between them,
therefore if one is changed the other one must be updated accordingly.
The obvious solution is to use
(defmethod modify-slot1 (new-value)
(setf (slot1 class) new-value)
(setf (slot2 class) (f new-value)))
and the same with slot2.
However, this solution does not look very elegant, and it does not
protect the slots from an accidental (setf (slot1 class) new-value)
elsewhere in the code.
Is there a better way to do this?
TIA
On Dec 14, 4:09 pm, proton <··········@gmail.com> wrote:
> I have two slots which must maintain a certain relation between them,
> therefore if one is changed the other one must be updated accordingly.
> The obvious solution is to use
> (defmethod modify-slot1 (new-value)
> (setf (slot1 class) new-value)
> (setf (slot2 class) (f new-value)))
> and the same with slot2.
Well, you can do this more cleanly by using an :AFTER method on your
accessor, like so:
(defclass a-class ()
((slot-1 :accessor slot-1)
(slot-2 :accessor slot-2)))
(defmethod (setf slot-1) :after (new-value (object class-1))
(setf (slot-2 object) (do-stuff new-value)))
Cheers,
Pillsy
proton wrote:
> Is there a way to have a method triggered automatically whenever a
> class slot is modified?
>
> I have two slots which must maintain a certain relation between them,
> therefore if one is changed the other one must be updated accordingly.
> The obvious solution is to use
>
> (defmethod modify-slot1 (new-value)
> (setf (slot1 class) new-value)
> (setf (slot2 class) (f new-value)))
>
> and the same with slot2.
Both ways? Could get tricky with my Cells package, depending on whether
the update to 2 leads to an update to 1 to an update to 2 and never
ends. As Alex suggested you can write your own writer method, but then
you still need to worry about cycling endlessly back and forth.
kt
--
http://www.theoryyalgebra.com/
"In the morning, hear the Way;
in the evening, die content!"
-- Confucius
Ken Tilton wrote:
>
>
> proton wrote:
>> Is there a way to have a method triggered automatically whenever a
>> class slot is modified?
>>
>> I have two slots which must maintain a certain relation between them,
>> therefore if one is changed the other one must be updated accordingly.
>> The obvious solution is to use
>>
>> (defmethod modify-slot1 (new-value)
>> (setf (slot1 class) new-value)
>> (setf (slot2 class) (f new-value)))
>>
>> and the same with slot2.
>
> Both ways? Could get tricky with my Cells package, depending on whether
> the update to 2 leads to an update to 1 to an update to 2 and never
> ends. As Alex suggested you can write your own writer method, but then
> you still need to worry about cycling endlessly back and forth.
You can check whether the value of one slot actually changes, and only
trigger an update of the other slot if that's the case.
Pascal
--
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
p> However, this solution does not look very elegant, and it does not
p> protect the slots from an accidental (setf (slot1 class) new-value)
p> elsewhere in the code.
slot1 is accessor -- it's a generic function. thus you can defmethod your
custom code. i think you need something like:
(defmethod (setf slot1) :after (new-value (object your-class))
(setf (slot-value object 'slot2) (compute-slot2-from-slot1 new-value))
certainly users (and you) can still bypass this mechanizm via slot-value,
and we can hook this too, but i think there's no need.
there are other options too: if you can compute slot2 from slot1, you can
just not have such slot, but two methods:
(defmethod slot2 ((object your-class)) ...)
(defmethod (setf slot2)) (new-value (object your-class)) ...)
and "emulate" this slot2.
and if having related slots happens more than once in your applications,
check Cells (http://common-lisp.net/project/cells/)/
Alex Mizrahi wrote:
> p> However, this solution does not look very elegant, and it does not
> p> protect the slots from an accidental (setf (slot1 class) new-value)
> p> elsewhere in the code.
>
> slot1 is accessor -- it's a generic function. thus you can defmethod your
> custom code. i think you need something like:
>
> (defmethod (setf slot1) :after (new-value (object your-class))
> (setf (slot-value object 'slot2) (compute-slot2-from-slot1 new-value))
>
> certainly users (and you) can still bypass this mechanizm via slot-value,
> and we can hook this too, but i think there's no need.
>
> there are other options too: if you can compute slot2 from slot1, you can
> just not have such slot, but two methods:
>
> (defmethod slot2 ((object your-class)) ...)
> (defmethod (setf slot2)) (new-value (object your-class)) ...)
>
> and "emulate" this slot2.
>
> and if having related slots happens more than once in your applications,
> check Cells (http://common-lisp.net/project/cells/)/
>
>
I think we better start sending people here, all the links on that page
are useless (unless one points here <g>):
http://common-lisp.net/cgi-bin/viewcvs.cgi/cells/?root=cells
kt
--
http://www.theoryyalgebra.com/
"In the morning, hear the Way;
in the evening, die content!"
-- Confucius
proton wrote:
> Is there a way to have a method triggered automatically whenever a
> class slot is modified?
>
> I have two slots which must maintain a certain relation between them,
> therefore if one is changed the other one must be updated accordingly.
> The obvious solution is to use
>
> (defmethod modify-slot1 (new-value)
> (setf (slot1 class) new-value)
> (setf (slot2 class) (f new-value)))
>
> and the same with slot2.
>
> However, this solution does not look very elegant, and it does not
> protect the slots from an accidental (setf (slot1 class) new-value)
> elsewhere in the code.
>
> Is there a better way to do this?
1) Use accessors and define :after methods.
2) Define your own metaclass, and define an :after method on (setf
slot-value-using-class).
Pascal
--
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/