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

Alexander Schmolck a.schmolck at gmail.com
Sun May 7 22:32:48 CEST 2006


Bill Atkins <NOatkinwSPAM at rpi.edu> writes:

> Here's how one of the cells examples might look in corrupted Python
> (this is definitely not executable):
> 
>   class FallingRock:
>     def __init__(self, pos):
>       define_slot( 'velocity', lambda: self.accel * self.elapsed )
>       define_slot( 'pos', lambda: self.accel * (self.elapsed ** 2) / 2,
>                     initial_position = cell_initial_value( 100 ) )
>       self.accel = -9.8
> 
>   rock = FallingRock(100)
>   print rock.accel, rock.velocity, rock.pos
>   #     -9.8, 0, 100
> 
>   rock.elapsed = 1
>   print rock.accel, rock.velocity, rock.pos
>   #     -9.8, -9.8, -9.8
> 
>   rock.elapsed = 8
>   print rock.accel, rock.velocity, rock.pos
>   #     -9.8, -78.4, -627.2
> 
> Make sense?  

No, not at all.

Why do you pass a ``pos`` parameter to the constructor you never use? Did you
mean to write ``cell_initial_value(pos)``?

Why is elapsed never initialized? Is the dependency computation only meant to
start once elapsed is bound? But where does the value '0' for velocity come
from then? Why would it make sense to have ``pos`` initially be completely
independent of everything else but then suddenly reset to something which is
in accordance with the other parameters?

What happens if I add ``rock.pos = -1; print rock.pos ``? Will I get an error?
Will I get -1? Will I get -627.2?

To make this more concrete, here is how I might implement a falling rock:

class FallingRock(object):
    velocity = property(lambda self:self.accel * self.elapsed)
    pos = property(lambda self: 0.5*self.accel * self.elapsed**2)
    def __init__(self, elapsed=0):
        self.elapsed = elapsed
        self.accel = -9.8

rock =  FallingRock()
print rock.accel, rock.velocity, rock.pos
# => -9.8 -0.0 -0.0
rock.elapsed = 1
print rock.accel, rock.velocity, rock.pos
# => -9.8 -9.8 -4.9
rock.elapsed = 9
print rock.accel, rock.velocity, rock.pos
# => -9.8 -88.2 -396.9

How would you like the behaviour to be different from that (and why)?

> The idea is to declare what a slot's value represents
> (with code) and then to stop worrying about keeping different things
> synchronized.

That's what properties (in python) and accessors (in lisp) are for -- if you
compute the slot-values on-demand (i.e. each time a slot is accessed) then you
don't need to worry about stuff getting out of synch.

So far I haven't understood what cells (in its essence) is meant to offer over
properties/accessors apart from a straightforward efficiency hack (instead of
recomputing the slot-values on each slot-access, you recompute them only when
needed, i.e. when one of the other slots on which a slot-value depends has
changed). So what am I missing?
 
> Here's another of the examples, also translated into my horrific
> rendition of Python (forgive me):
> 
>   class Menu:
>     def __init__(self):
>       define_slot( 'enabled', 
>          lambda: focused_object( self ).__class__ == TextEntry and 
>                  

OK, now you've lost me completely. How would you like this to be different in
behaviour from:

class Menu(object):
    enabled = property(lambda self: isinstance(focused_object(self),TextEntry) \
                                    and focused_object(self).selection)
    
???
   
> Now whenever the enabled slot is accessed, it will be calculated based
> on what object has the focus.  Again, it frees the programmer from
> having to keep these different dependencies updated.

Again how's that different from the standard property/accessor solution as
above?

'as



More information about the Python-list mailing list