[cells-devel] Something like a def-family-observer?

Peter Hildebrandt peter.hildebrandt at gmail.com
Wed Dec 12 15:14:47 UTC 2007


On Wed, 12 Dec 2007 13:27:06 +0100, Ken Tilton <kennytilton at optonline.net>  
wrote:

> Ken Tilton wrote:
>> Peter Hildebrandt wrote:
>>  OK, now that I am up to speed, let's go back to your original query.
>>
>>>
>>> Say, I have a model M that depends on the structure of a family tree.   
>>> One  of M's slots is therefore depending on the root of the family  
>>> tree: (c?  root).  However, I want M to know about changes in the  
>>> family tree, like,  say, when a child or grandchild is added.   
>>> Apparently cells (at least the  cells_2.0 branch required by  
>>> cells-gtk) does not broadcast change messages  to the parents of a  
>>> node (which I guess is the right thing in 99% of the  cases).
>>>
>>> What's the best way to deal with that?
>>>
>>> (i) Is there some mechanism for this purpose present in cells? Or
>>> (ii) Do I roll my own special case solution? Or
>>> (iii) Is it worthwhile to build some general purpose solution to this   
>>> problem?
>>>
>>> My approach towards (ii) (I haven't coded anything yet, waiting for  
>>> you  comments) would be something like building an observer tree each  
>>> node of  which observes one node in the family tree.  Something like  
>>> this:
>>> - Design a tiny tree observer model ("tto"?), suited to observing one   
>>> family node
>>> (defmodel tty (family) (observed observed-kids reports-to))
>>>
>>> - Every tto knows about the parent model (M from above) and does the  
>>> right  thing when it sees a change (say, call a closure)
>>> - If the observed nodes has kids, it instantiates tto kids of its own  
>>> to  match the kids of the observed tree
>>>    (def-c-output observed ((self tto))
>>>      (make-tto :observed (c? new-value) :observed-kids (c? (kids   
>>> new-value)))
>>>      (setf (kids self) (mapcar (lambda (kid) (make-tto :observed (c?  
>>> kid)  :observed-kids (c? (kids kid)))) (kids new-value)
>>>    ...)
>>>    (def-c-output observed-kids ((self tto))
>>>    ...)
>>>
>>> - Changing the root slot in M results in the instantiation of a tto  
>>> for  the root
>>>
>>> I guess that would work ... but I feel there must be a more elegant   
>>> solution.
>
> Roughly (cuz of rough recall of Cells2):
>
>
> (defmodel family-observer (family)
>     ;; we'll use the "md-value" slot for the observed
>    ()
>    (:default-initargs
>       :kids (c? (the-kids
>                   (bwhen (o (^md-value self)) ;; not sure why not
>                    (loop for k in (^kids o) collecting
>                       (let ((this-k k)) ;; loop is weird
>                          (make-instance 'family-observer
>                             :md-value this-k)))))))
>

Thanks!  The following does the trick (incl. some rewriting)

   :kids (c?
      (the-kids			; follow changes of our source
         (when (^md-value) ;; not sure why not
           (mapcar #'(lambda (k) (make-instance 'family-observer :md-value  
k)) (kids (^md-value))))))))

> That handles rows in/out.

Actually, I don't quite see how it handles rows out.  Where do I put stuff  
to properly clean out the old kids?

Can I do something like (c?  (mapcar #'not-to-be (^kids)) (the-kids  
...)))  ?  (looks wrong)

> As for individual values, well, I guess you generalize the handling of  
> kids so it is just another slot-value. Changes to kids add/remove rows,  
> changes to other things set values within a row.

That's easier, because the number is constant.  So a simple def-c-output  
will do.

> You know you need the kids handled, so what you might build that in and  
> then have some macrology write the defmodel for custom subclasses of f-o:
>
> (def-family-observer my-tree (<def options?>) slot-1 slot-2)

Yep.  Thought of something like this.  My plan was to supply a generic  
function for making child observers like

(def-f-o my-obs (#'mk-observer) slot-1 slot-2)

then the :kids cell will not call plain make-instance, but mk-observer,  
which can specify on the source, so if you have a mixed family of people  
and dogs

(def-f-o person-obs (#'mk-observer) name age)
(def-f-o dog-obs (#'(lambda (&rest initargs) (apply #'make-instance  
'dog-obs initargs)) race favorite-ball)

(defmethod mk-observer ((self person) &rest initargs)
   (apply #'make-instance 'person-obs self initargs))

(defmethod mk-observer ((self dog) &rest initargs)
   (apply #'make-instance 'dog-obs initargs))

Or simply

(def-f-o person-obs (person) name age)
(def-f-o dog-obs (dog) race favorite-ball)

> Expansion left as an exercise. :)

> It is not inconceivable to have f-o link dynamically to any  
> cell-mediated slot of the model instances, btw.

Is there some cells hook to get the list, or would that involve messing  
with MOP?

Peter

>
> kt
>





More information about the cells-devel mailing list