[cells-devel] Re: Cells MOP / installing rules

Kenny Tilton ktilton at nyc.rr.com
Wed Dec 3 17:26:50 UTC 2003


I thought I'd slide over to cells-devel to get this in the archive.

Thomas F. Burdick wrote:

>Kenny Tilton writes:
> >
> > I'll give you a lead. Look at to-be/md-awaken/c-awaken and 
> > not-to-be/md-quiesce/c-quiesce. There is also a whole suite of c-link* 
> > and c-unlink* guys. Come to think of it, unlinking from unused cells 
> > handles both pointers (each way between user and used). Likewise 
> > linking. so to swap in a cell (roughly):
>
>Aarg, "quiesce".  I was wondering if there was an opposite of awaken.
>
"quiesce" was especially good during the c-gosub years (and, yes, the 
"gosub" is in fun/fond memory of The Early Years) when a cell would 
actually jump back in once the gosub "returned". btw, I forgot to answer 
about the mechanism. I forget, actually. IIRC, it was somewhat 
imperative, in that at some point one simply instantiated a gosub 
dynamically aiming it at the instances to which it applied (a to-be 
:after method on gosub could swap in any number of cells for any number 
of instances). One fun thing was that this was a case where Cells was 
implemented using Cells: the gosub instance had a "return" cell, which 
echoed a T value by backing out its cells and restoring the quiesced Cells.

I finally decided there must be a way to express the page-thumb 
positions cyclicity as a single rule always in effect, and liked the 
idea of yanking the entire gosub mechanism. Only I ended up just having 
each other setf the other, each a CV setf'ed by something else!! 
Hmmmmm.....probably the best way to go is hunker down and just make the 
cyclicity work, but first I want to fix propagation and see if I can 
lose the horrid dataflow interference handling (which stopped my first 
attempt at allowing cyclically dependent rules.

>
> >     (let ((users (c-users old-cell)))
> >         (c-quiesce old-cell)
> >         (dolist (u users)
> >             (c-link u new-cell))
> >        (c-awaken new-cell))
> >
> > But then I can see a problem since c-awaken thinks it is getting a brand 
> > new cell, when new-cell should actually assume life as if it had been 
> > there all along--it needs to compare its first value calculated with the 
> > last value calculated by the old cell to keep all the contracts working.
>
>Yeah, I'd noticed that.  I figured I'd follow the normal
>cell-installation path, and check for begining-of-the-world
>assumptions.  I got there with c-install pretty quickly (it doesn't
>look for a preexisting cell).
>
That would likely get shot down at the higher setf level, which (until 
Cloucell) simply rejected any attempt to store a cell in a slot 
(becasuse it usually meant a bleary edit session had yielded (c? 
blah-blah (c?......)). But then Cloucell wanted to have a generic model 
view which dynamically switch to the current model inspected by mapping 
cell view kids one by one to cell slots, ie, a rule picked out the cell 
as the md-value of the corresponding cell view.

>
> > btw, are you sure you need to do this? When will you know to switch 
> > rules? If that is model data, can't you just:
> > 
> >      (c? (if (^time-to-switch)
> >                <compute this-a-way>
> >                <compute that-a-way>))
>
>This works in most cases, but it can be a mess in larger systems.  You
>can always work around it by making slot FOO do:
>
>  (c? (funcall (^foo-worker)))
>
>then just replacing FOO-WORKER, but it seems cheesy to me.
>
>I don't absolutely need to do this right now (I've been mostly hacking
>up silly small Cells examples for myself).  But I was thrilled with
>this feature of KR when working on the Anaconda compiler.  I used KR
>to maintain constraints in the code graph.  When working on the
>analysis phase(s) that ran before the optimizer(s), it was nice to be
>able to change rules when the analyzer discovered it could.
>
>Say the analyzer found that a certain significant area of the program
>graph didn't do any allocation, or did a small amount where we were
>able to statically determine the ceiling.  This means that we don't
>necessarily need to keep our values tagged in that part of the
>graph[*].  Cool.  We go through that area, and change the rules to that
>effect.  It was good to keep the o-formulas the same part of the same
>file, where the analysis happened, not spread throughout the formulas
>of the program grapher.
>
>[*] Even better/worse, we do potentially need the all-tagged code,
>because Lisp is dynamic.  So, we duplcate that part of the graph, to
>ensure that code gets compiled under the old rules, *and* we modify
>the primary code to use the new rules.  You multiply this across M
>dimensions of analysis, and you can't use booleans as hacks, you
>really need seperate worlds of rules.
>
Gotcha. This is a compiler and you want the compiler overhead out of the 
picture at run-time. But then you must already be solving the problem: 
"the compiler has decided this and that, now how do we leave things so 
this and that obtain at run time?" Oh, well, sounds like you know what 
you are doing, I'll shut up.

>
> > btw2, are you soloing on this as an exercise in learning Cells? Because 
> > I fully expect to be making such extensions myself (well, OK, where they 
> > make sense--but in this case I would do it for you even if I decided it 
> > was not something I wanted to have in the main fork--but again, as long 
> > as it does not break anything, I would err on the side of inclusiveness 
> > and just express my misgivings in the doc.
>
>I've gotten quite used to being able to depend on KR, and I'm
>seriously considering Cells as a permanent replacement.  I like what
>I've seen so far, so I kept digging; I want to ensure that it's good
>as far down as I've dug with KR -- rough edges notwithstanding, so far
>so good, btw :-).  So, yes, partly it's an exercise in learning Cells'
>guts.  Also, I started by pulling a Model (do you have a term for an
>instance with cell-slots?)
>
yes, "model". re-badging possible: I actually just got quite confused 
over here tidying up things so I could yank some apologies from the doc. 
Not sure I am done, because unhappily I just realized that DEFMODEL does 
not create a subclass of MODEL. :( It subclasses MODEL-OBJECT. The right 
thing is to change model-object to ORGANISM or some other pun for a 
cells-aware object, then change DEFMODEL to DEFORGANISM. This is 
something I am after anyway, because even though in my world Cells mean 
model-building, strictly speaking the MODEL thing is just one way to 
play with cells.

> into the inspector, and kept going.  I'd
>inspect, code, inspect, code, then discover that the code I'd written
>was already in Cells.  So, it wasn't until I hit questions like, "has
>Kenny thought of this/is this supported?" that I thought to ask for
>help.  Not to mention that my spare time has been fleeting over the
>last couple weeks.
>
> > >And, I was doing something stupid.  The latest version of MAKE-BLAST
> > >(think I got it right, finally) wasn't special-casing slots that get
> > >inherited from MODEL-OBJECT.  That means, that .CELLS wasn't an alist
> > >in the resulting blast, it was a cell pointing to its prototype's
> > >.CELLS.  That, uh, breaks.
> >
> > This will be interesting to see. So when you clone via make-blast, the 
> > new instance keeps up with the original by having a cell in each slot 
> > which says:
> > 
> >      :slotX (c? (slotX (original self)))
> > 
> > Just guessing.
>
>Pretty much, except closing over the prototype, instead of using a
>slot. 
>
(Aside: the body of make-blast-of-class did not answer the question I 
formed at this point, so my follow-up is here but I did not check out mboc.)

If (a) the rule for slotX is:

    :slotX (c? (+ (^slotY) (^slotZ))

and (b) the blast can substitute a different rule for slotZ, then there 
would be a problem. Or do blasts always accept the prototype in its 
entirety? I'll just leave you with my main concern: Cells to me feel 
"instance-oriented", in that even where they have the same rule for the 
same slot, those rules can look to attributes of the instance (such as 
its position in the list of kids of its parent) when computing a value. 
(So even if slotZ is not overridden the semantics get mixed up.)

If you try just to re-use the Cell, the problem is that Cells gain 
instance-specific state once installed and evaluated (the model, users, 
useds).

I guess this is the classic case of deep vs shallow copy. What does 
"same as prototype" mean?

> The body to MAKE-BLAST-OF-CLASS is currently:
>
>  ;; PARITION-SLOTS-FOR-BLAST makes the policy of who gets inherited
>  ;; from the prototype, who gets the default value, according to
>  ;; CLOS, and who is specified with initargs.
>  (defun make-blast-of-class (prototype class &rest initargs)
>    (let ((class (if (symbolp class) (find-class class) class)))
>      (multiple-value-bind (initargs inherited default)
>          (partition-slots-for-blast prototype class initargs)
>        (declare (ignore default))
>        (let ((blast (apply #'make-instance class initargs)))
>          (loop for slot in inherited
>                for slot-name = (slot-definition-name slot)
>                do (install-cell blast slot-name
>                                 (make-echo-cell prototype slot-name))
>                finally (bring-to-life blast))
>          blast))))
>
>
> > But if so, I wonder if we cannot optimize that by having the
> > original simply keep track of its clones, and throwing in a
> > mechanism to identify which slots were accepted as is from the
> > original (I am just guessing wildly at the spec). Then you don't
> > get all the slots with redundant links.
>
>I'm not sure that a list of blasts would be any more efficient than a
>bunch of slots in environments, but if it were, and it were more
>optimal in Cells' internal dependency tracking, that would probably be
>a good idea.  My mind is still very much in lazy mode, so pushing the
>prototype's values into the blasts didn't occur to me.
>
OK. I was thinking especially of the case where a class had a lot of 
slots, and that it would be more efficient for the original to remember 
one blast than for each blast slot to remember the original slot.

>
> > btw, the function md-slot-cell-type (I think! I have just been hacking 
> > that and may hvae changed something) returns nil for non-cell slots. 
> > Also, I very recently changed the default on the :cell option from nil to t.
>
>I was debating with myself as to whether a blast should use a rule for
>non-cell slots, or cv slots, or ... I tentatively decided that every
>prototype inherited slot should be ruled.  Mixing prototypes and class
>instantion, plus constraints, makes for a lot of abutting edges.  I
>think I'm happy with this formulation for blasts, so once it's
>working, I think I'll try a knowledge representation problem, and see
>if it still holds up.
>
OK, sounds like you are happy, I'll lay off the backseat driving unless 
you choose to pursue anything above.

kt

-- 
http://tilton-technology.com

Why Lisp? http://alu.cliki.net/RtL%20Highlight%20Film 

Your Project Here! http://alu.cliki.net/Industry%20Application






More information about the cells-devel mailing list