[cells-devel] How does cells deal with in-place modification of slot values?

Ken Tilton kennytilton at optonline.net
Mon May 19 11:25:56 UTC 2008


Larry Clapp wrote:
> See subject.
> 
> In other words, say I have a class with two slots, a and b, with b
> sort-of dependant on a:
> 
>   (defmodel test ()
>     ((a :initarg :a :initform (c-in (list 'a)) :accessor a)
>      (b :initarg :b :initform (c? (car (^a))) :accessor b)))
> 
>   (defmethod print-object ((self test) stream)
>     (print-unreadable-object (self stream :type t :identity t)
> 	(format stream "a: ~S, b: ~S" (^a) (^b))))
> 
>   (setf *a* (make-instance 'test))
> 
>   CELLS 11 > *a*
>   #<TEST a: (A), b: A 22ED4D93>
> 
>   CELLS 12 > (setf (car (a *a*)) 'd)
>   D
> 
>   CELLS 13 > *a*
>   #<TEST a: (D), b: A 22ED4D93>
> 
> Slots a and b are now out of sync.  What's the ideo-cells-ic way to do
> this?
> 
> What I'm really trying to do is wrap a class around somebody else's
> object.  The internal state of the object changes, and I'd like to
> figure out some way to make the Cells system aware of the change.
> 
> "Native" use of the object is something like this
> 
>   (some-other-package:perturb-test self)
> 
> Do I need to wrap perturb-test too?  e.g.
> 
>   (defmodel test ()
>     ((a :initarg :a :initform (c-in (list 'a)) :accessor a)
>      (a-changed :initform (c-in 0) :accessor a-changed)
>      (b :initarg :b :initform (c? (and (^a-changed) (car (^a)))) :accessor b)))
> 
>   (defmethod print-object ((self test) stream)
>     (print-unreadable-object (self stream :type t :identity t)
>       (format stream "a: ~S, b: ~S" (^a) (^b))))
> 
>   (setf *a* (make-instance 'test))
> 
>   (defun perturb-test (self y)
>     (prog1
> 	(setf (car (^a)) y)
>       (incf (^a-changed))))

[Sorry, I did not even read this far last time because I thought I 
understood what you were asking.]

If this last bit is an option, ie, if /I/ am the one setf-ing the car, 
then we do not have the case I feared of the foreign package mutating 
state behind my back, and in fact this problem arises even without a 
foreign object: I would have the same problem any time I was mutating 
state in a slot of even a vanilla Cells-powered class. So...

It does not come up a lot, so I Just Do Not Go There -- I am careful to 
recons the list. This flies in the face of a Cells design imperative (no 
exposed wiring) but like I said, it does not come up much. Usually the 
kids slot of a GUI composite widget, where I really do not want to 
regenerate all the sub-widgets just to add/remove one. Then I map over 
the .cache (this usually being in a Cell rule for kids) making a new 
list but generally keeping the car of each cons copied.

I think if it /did/ become a problem I would jazz up Cells with a 
cells-aware accessor (^elt? ^nth?) to read and write elements of a 
list/sequence, leaving elt and nth (and (setf car)) as backdoors.

Not as transparent as shadowing CAR, but the self-documentation quality 
is a nice compensation for that, and shadowing CAR scares me 
performance-wise and in general.

Even then I think there would be an inefficient (but ineluctable) 
dependency not on the car per se but on any change to the list. What if 
the case were CADDR instead of CAR? Now there are dependencies on two 
CDRs and one CAR, yes? Because if I, say, (rplacd X (cddr X)), then the 
result of (caddr X) is different and anyone accessing that cellsily will 
need to recalculate.

Hmmm. I am reminded why I do not address these things until an 
application forces me to. :)

kenny



More information about the cells-devel mailing list