A critic of Guido's blog on Python's lambda
kentilton at gmail.com
Tue May 9 00:46:57 CEST 2006
David C. Ullrich wrote:
> On 08 May 2006 12:53:09 -0700, tfb at conquest.OCF.Berkeley.EDU (Thomas
> F. Burdick) wrote:
>>Ken Tilton <kentilton at gmail.com> writes:
>>>No, you do not want on-change handlers propagating data to other
>>>slots, though that is a sound albeit primitive way of improving
>>>self-consistency of data in big apps. The productivity win with
>>>VisiCalc was that one simply writes rules that use other cells, and
>>>the system keeps track of what to update as any cell changes for
>>>you. You have that exactly backwards: every slot has to know what
>>>other slots to update. Ick.
>>No no, that's fine and the way it should be: when you change a slot,
>>it should know who to update. And that's also the way it works in
>>Cells. The trick is that Cells takes care of that part for you:
> I'm glad you said that - this may be what he meant, but it seems
> more plausible than what he actually said.
There may be some confusion here because there are two places for code
being discussed at the same time, and two sense of propagation.
the two places for code are (1) the rule attached to A which is
responsible for computing a value for A and (2) a callback for A to be
invoked whenever A changes. Why the difference?
In Cells, A is a slot such as 'background-color'. Whenever that changes,
we have to do something more. On Mac OS9 it was "InvalidateRect" of the
widget. In Cells-Tk, it is:
(Tcl_interp "mywidget configure -background <new color>")
In my OpenGL GUI, it is to rebuild the display-list for the widget.
That is the same no matter what rule some instance has for the slot
background-color, and different instances will have different rules.
As for propagating, yes, Cells propagates automatically. More below on
that. What I saw in the example offered was a hardcoded on-change
callback that was doing /user/ propagation form B to A (and B to A! ...
doesn't that loop, btw? Anyway...)
>>the *programmer* has to care about is what values a slot depends on --
>>Cells takes care of inverting that for you, which is important because
>>that's a job that a computer is much better at than a human.
> Fine. I suppose that is better; if b is going to return a + 1
> the fact that this is what b returns should belong to b, not
> to a. So a has an update list including b, so when a's value
> is set a tells b it needs to update itself.
> If we're allowed to pass (at some point, to some constructor
> or other) something like (b, a + 1, [a]), which sets up a
> cell b that shall return a + 1, and where the [a] is used
> in the constructor to tell a to add b to a's update list
> then this seems like no big deal.
> And doing that doesn't seem so bad - now when the programmer
> is writing b he has to decide that it should return a + 1
> and also explicitly state that b shall depend on a; this
> is all nice and localized, it's still _b_ telling _a_ to
> add b to a's update list, and the programmer only has
> to figure out what _b_ depends on when he's writing _b_.
> Doesn't seem so bad.
> But of course it would be better to be able to pass just
> something morally equivalent to (b, a + 1) to whatever
> constructor and have the system figure out automatically
> that since b returns a + 1 it has to add a to b's update
> list. There must be some simple trick to accomplish that
> (using Python, without parsing code).
Right, you do not want to parse code. It really would not work as
powerfully as Cells, which notice any dynamic access to another cell
while a rule is running. So my rule can call a function on "self" (the
instance that wons the slot being calculated, and since self can have
pointers to other instances, the algorithm can navigate high and low
calling other functions before finally reading another ruled slot. You
want to track those.
> Exactly what the trick is I
> don't see immediately.
To compute a value for a slot that happens to have a rule associated
with it, have a little cell datastructure that implements all this and
associate the cell with the slot and store a pointer to the rule in the
cell. Then have a global variable called *dependent* and locally:
currentdependent = *dependent*
oldvalue = cell.value
newvalue = call cell.rule, passing it the self instance
*dependent* = currentvalue
if newvalue not = oldvalue
call on-change on the slot name, self, newvalue and oldvalue
(the on-chnage needs to dispatch on as many arguments as
the language allows. Lisp does it on them all)
In the reader on a slot (in your getattr) you need code that notices if
the value being read is mediated by a ruled cell, and if the global
*dependent* is non empty. If so, both cells get a record of the other
(for varying demands of the implementation).
> In Cells do we just pass a rule using other cells to
> determine this cell's value, or do we also include
> an explicit list of cells that this cell depends on?
Again, the former. Just write the rule, the above scheme dynamically
figures out the dependencies. Note then that dependencies vary over time
because of different branches a rule might take.
I want to reassure the community that this (nor the spreadsheet analogy
<g>) is not just my crazy idea. In 1992:
"It is becoming increasingly evident that imperative languages are
unsuitable for supporting the complicated flow-of-control that arises in
interactive applications. This paper describes a declarative paradigm
for specifying interactive applications that is based on the spreadsheet
model of programing. This model includes multi-way constraints and
action procedures that can be triggered when constraints change the
values of variables."
Cells do not do multi-way constraints, btw. Nor partial constraints. To
hard to program, because the system gets non-deterministic. That kinda
killed (well, left to a small niche) the whole research programme. I
have citations on that as well. :)
"Have you ever been in a relationship?"
Attorney for Mary Winkler, confessed killer of her
minister husband, when asked if the couple had
More information about the Python-list