A critic of Guido's blog on Python's lambda

David C. Ullrich ullrich at math.okstate.edu
Tue May 9 12:35:47 CEST 2006


On Mon, 08 May 2006 18:46:57 -0400, Ken Tilton <kentilton at gmail.com>
wrote:

>
>
>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? 

No, there's no looping in the example. Yes, the code determining what
b returns should be attached to b instead of to a, but the code I
gave does work as advertised. (I mean give me a break - I provided
a sample use so you could simply run it. Installing Python is not
hard.)

If you, um, look at the code you see that "cells.a = 42" triggers
cells.__setattr__, which fires a's callback; the callback then
reaches inside and sets the value of b _without_ going through
__setattr__, hence without triggering b's callback.

In Cells you can't have A depend on B and also B depend on A?
That seems like an unfortunate restriction - I'd want to be
able to have Celsius and Farenheit, so that setting either
one sets the other.

Of course if there are no loops it's easier to see how
you managed to do the stuff you were talking about elsewhere,
(at least sometimes) delaying execution until needed.

>Anyway...)
>
>> 
>> 
>>>all
>>>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:
>
>     http://www.cs.utk.edu/~bvz/active-value-spreadsheet.html
>
>"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. 

My _guess_ is that a "multi-way constraint" is something like
what's above, where A depends on B and B depends on A?

>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. :)
>
>kenny


************************

David C. Ullrich



More information about the Python-list mailing list