[Python-Dev] anonymous blocks

Glyph Lefkowitz glyph at divmod.com
Tue Apr 19 22:27:57 CEST 2005


Guido van Rossum wrote:

> But what exactly are you trying to accomplish here? I think that
> putting the defs *before* the call (and giving the anonymous blocks
> temporary local names) actually makes the code clearer:

I'm afraid that 'block1', 'block2', and 'doFoo' aren't really making 
anything clear for me - can you show a slightly more concrete example?

> def block1(a, b):
>     return a + b
> def block2(c, d):
>     return c + d
> items.doFoo(block1, block2)

Despite being guilty of propagating this style for years myself, I have 
to disagree.  Consider the following network-conversation using Twisted 
style (which, I might add, would be generalizable to other Twisted-like 
systems if they existed ;-)):

def strawman(self):
     def sayGoodbye(mingleResult):
         def goAway(goodbyeResult):
             self.loseConnection()
         self.send("goodbye").addCallback(goAway)
     def mingle(helloResult):
         self.send("nice weather we're having").addCallback(sayGoodbye)
     self.send("hello").addCallback(mingle)

On the wire, this would look like:

     > hello
     < (response) hello
     > nice weather we're having
     < (response) nice weather we're having
     > goodbye
     < (response) goodbye
     FIN

Note that the temporal order of events here is _exactly backwards_ to 
the order of calls in the code, because we have to name everything 
before it can happen.  Now, with anonymous blocks (using my own pet 
favorite syntax, of course):

def tinman(self):
     self.send("hello").addCallback(def (x):
         self.send("nice weather we're having").addCallback(def (y):
             self.send("goodbye").addCallback(def (z):
                 self.loseConnection())))

Now, of course, this is written as network I/O because that is my 
bailiwick, but you could imagine an identical example with a nested 
chain of dialog boxes in a GUI, or a state machine controlling a robot.

For completeness, the same example _can_ be written in the same order as 
events actually occur, but it takes twice times the number of lines and 
ends up creating a silly number of extra names:

def lion(self):
     d1 = self.send("hello")
     def d1r(x):
         d2 = self.send("nice weather we're having")
         def d2r(y):
             d3 = self.send("goodbye")
             def d3r(z):
                 self.loseConnection()
             d3.addCallback(d3r)
         d2.addCallback(d2r)
     d1.addCallback(d1r)

but this only works if you have a callback-holding object like Twisted's 
Deferred.  If you have to pass a callback function as an argument, as 
many APIs require, you really have to define the functions before 
they're called.

My point here is not that my proposed syntax is particularly great, but 
that anonymous blocks are a real win in terms of both clarity and 
linecount.  I'm glad guido is giving them a moment in the limelight :).

Should there be a PEP about this?


More information about the Python-Dev mailing list