[Python-3000] A plea for anonymous functions

Fredrik Lundh fredrik at pythonware.com
Thu Nov 16 15:54:20 CET 2006


Antoine wrote:

> >      response = (yield server.get_synset_links())
> >      format_expanded(li.content, response.related)
>
> This assumes there is an underlying event loop of some sort that accepts
> and is able to schedule generators.

no, it only assumes that whoever called your code is set up to schedule
communication tasks on your behalf.  that's how asyncronous network
stuff is usually done, so I'm not sure why you're using this as a counter-
argument.

> Much more annoyingly, all your "yield"'s must be in the same scope, they
> can't be spread in various subfunctions called from the generator

dealing with nested generators is simple; a bit tedious, but far from impossible.

>>      def handle_response(record):
>>          format_expanded(li.content, response.related)
>>      server.get_synset_link(handle_response)
>
> As already mentioned, the problem with this idiom is that code that is
> executed *after* appears *before* the "get_synset_link".
> It makes the code less straightforward to write and especially to read
> (and having readable code is important).

why?  it *separates* the two things, and lets you concentrate on one thing at a
time.  I'm far from convinced that that's a drawback, especially when both the
request construction and the response handlers gets more complex than what
you can fit in a line of code or three.

it also makes it a *lot* easier to test and debug the callbacks, makes it easier
to refactor both the request-generating code and the response handlers, makes
it easier to reuse response handlers for related tasks, is self-documenting, given
appropriate callback names, and generally, in my experience, leads to much
better code quality.

>>      with async server.get_synset_link() as response:
>>          format_expanded(li.content, response.related)
>
> How is this one supposed to work ? What is "with async blah()" ?

a magic thing that runs the code block behind the covers, of course.  requires a
non-released version of the from __future__ statement, at the time.  unlike the
following syntax:

@server.get_synset_link()
def block(response):
    format_expanded(li.content, response.related)

which actually works in today's Python.

>> No, I said that under your proposal, you're trading two lines of code
>> that looks like Python for two (or three) lines of code that looks like
>> something else.
>
> The problem is not merely related to the number of lines of code. It is a
> readibility problem. Having the callback enclosed in a the function call
> which registers it makes the code more readable than defining the callback
> beforehand.

but here we're back to the "it seems to me" kind of argumentation.  show us the
code, and don't just argue that you really meant to post something else when people
point out how lousy your example is.

> Saying this does *not* mean one is a Javascript programmer (I hate
> Javascript, but this particular point of Javascript is superior to what
> Python has to offer).
>
>> So show us some sugar, then.  After all, Python's design is driven by by
>> an urge to simplify real usage patterns that's been observed in the
>> wild,
>
> Real usage patterns of event-driven code can be seen everywhere from GUI
> applications to network applications (written with Twisted).
> In many applications it is arguably much more common than the
> "try..finally" constructs that "with" attempts to simplify.

yeah, exactly.  so what kind of sugar would help event-driven programmers to
write better, shorter, more maintainable code ?  you and tomer want more onions
in your soup; perhaps there are other Twisted hackers out there with other ideas ?

>> Also see the "Patterns are signs of weakness in programming languages"
>> discussions:
>
> I would agree with this argument if I could understand how it relates to
> the current discussion. Are you saying anonymous functions are a "design
> pattern" ? (then what is *not* a design pattern ?).

no, the code that you argue would improved by anonymous blocks implement
a specific pattern, of course (a handler for an asyncronous event).  you're still
stuck thinking on mechanisms, I'm trying to get you to talk about use cases.

> What is more "invisible", including the callback straight at the point
> where it is registered, or defining it beforehand?

an invisible solution would be let you write asyncronous event handlers in a way
where you weren't even noticing that you were creating callbacks.  I have no idea
what it would look like, but ideally, it should be a bit like anonymous blocks in
for-in loops: they're been in there for ages, everyone is using them, but people
still claim that Python doesn't have anonymous blocks at all.

</F> 





More information about the Python-3000 mailing list