[Python-3000] A plea for anonymous functions

Talin talin at acm.org
Fri Nov 17 10:41:53 CET 2006


Greg Ewing wrote:
> Talin wrote:
> 
>> From my point of view, both 'with' and generator expressions are 
>> limited, special-case solutions to a general problem - the desire to 
>> be able to use and manipulate unnamed blocks of code as first-class 
>> objects.
> 
> I don't think it's as simple as that. Back when the with
> statement was first being discussed, I suggested that it
> should be implemented by passing the body as an anonymous
> function. That would have been a very simple way of doing
> it, but there were problems, such as what to do if the
> body contained break or continue statements. In the end,
> Guido rejected the anonymous-function approach, and we
> ended up with something that is rather more elaborate.
> 
> So we have a situation where there was no syntactical
> barrier to treating a code block as an anonymous function,
> but we chose not to do so. That seems to cast doubt on
> the idea that first-class code blocks would solve all
> the problems you suggest they would solve.

Well, it seems that my argument about being able to construct the 'with' 
statement with anon. code blocks may not be air-tight; However I still 
stand by my basic argument that anon. code is a fundamental 
building-block of a number of interesting language extensions, and that 
I expect to see a series of special-case syntactical work-arounds that 
compensate for the lack of such a feature.

To give a concrete example, suppose we decide to add to Python a 
special-case syntactical structure to deal with asynchronous events, 
similar to the code example that I posted earlier. The simplest possible 
example I can think of is an an alarm-clock function:

    # Create a callback timer
    alarm = Timer()
    alarm.SetDuration( 100, Timer.Milliseconds )

    upon alarm:
       print "It's time to get up, silly-head!"

    print "Alarm has been set!"

In the example, the hypothetical 'upon' statement passes a reference to 
the following suite to the object resulting from the expression - so in 
this case, the suite containing the print statement is passed as a 
callable to the 'alarm' object. Thus it is equivalent to:

    # Create a callback timer
    alarm = Timer()
    alarm.SetDuration( 100, Timer.Milliseconds )

    def upon_alarm():
       print "It's time to get up, silly-head!"

    alarm.set_callback( upon_alarm )

    print "Alarm has been set!"

The latter approach is a common pattern in Python. However, if we take 
the argument presented in the blog entry cited by Fredrik, which 
proposes that 'design patterns are symptomatic of a weakness in a 
programming language' (an argument which I don't entirely buy - absence 
of a feature is not always a weakness), then in order to make the 
language 'stronger', we ought to make the design pattern disappear into 
the language. In this case, we do so by absorbing the setup of the 
function machinery into the syntax of the 'upon' statement.

However, this special-case approach is flawed in this example, because 
its use is so narrow. If you think about it for a minute, you 
immediately start to imagine all of the things that 'upon' ought to deal 
with that it doesn't. For example, it has no way to deal with error 
callbacks; It has no way to pass arguments from the asynchronous process 
to the code block. It doesn't let me build a hash table of code snippets 
(which is my solution to the problem of 'switch' statements in Python.)

But even if we spend the next month writing a PEP for an 'upon' 
statement that overcomes all these limitations, I will still most likely 
be able to think of some use case that it doesn't handle. No matter what 
I add to the PEP, there will eventually be another PEP that adds yet 
another special-case solution to some aspect that I haven't covered. 
Instead, I'd rather work at a more fundamental level, that solves a 
larger class of problems.

(To the folks that would say that this is only a trivial optimization, I 
would respond - if that's the case, then why is it used so heavily in 
languages which do support it? And why does practically every other 
popular scripting language except Python support it at all? And no, the 
answer 'you shouldn't be programming in Python' is not an acceptable 
response, it's a lame cop-out IMHO.)

-- Talin



More information about the Python-3000 mailing list