[Python-3000] A plea for anonymous functions
Talin
talin at acm.org
Thu Nov 16 11:50:50 CET 2006
Fredrik Lundh wrote:
> Talin wrote:
>
>> The problem with providing use cases is that each one individually
>> doesn't carry much weight. When I do Javascript/AJAX programming, I use
>> anonymous functions quite a bit, as in the following example:
>>
>> do_command( 'get_synset_links', {}, function( response_data ) {
>> format_expanded( li.content, response_data.related )
>> })
>>
>> 'do_command' calls a function on the server side via an async HTTP
>> request, and calls the callback when the data is ready. By using an
>> anonymous function as the callback, I can group the request for the data
>> and the use of that data together in a logical way.
>
> Your specific example would probably be written:
>
> server.get_synset_links(
> lambda rec: format_expanded(li.content, rec.related)
> )
Only if the code in the block is a one-liner.
> in today's Python, which I find a bit easier to read than your slightly
> bloated JavaScript example.
>
> How do you handle errors, btw?
For this app, internally in the do_command function. In any case, error
handling code can be assumed to have been omitted for clarity.
>> Could I do the same thing using a named callback? Sure. Would it be as
>> easy to read and as clear?
>
> Well, if you find that easy to read and clear, I suspect you're more of
> a JavaScript programmer than a Python programmer. Here's how a more
> general form of the above would look in Python:
>
> response = (yield server.get_synset_links())
> format_expanded(li.content, response.related)
>
> or
>
> def handle_response(record):
> format_expanded(li.content, response.related)
> server.get_synset_link(handle_response)
>
> or perhaps
>
> with async server.get_synset_link() as response:
> format_expanded(li.content, response.related)
None of these are functionally equivalent to my code example, if I am
understanding them correctly.
But I guess I need to explain a bit more about my example.
First, 'get_synset_links' is a URL, not a method name. (More
technically, it's a fragment of a URL). I suppose you could play tricks
with __getitem__ to turn a method call into a URL, but I wouldn't do
that - for one thing, not all URLs can be represented as method names.
More importantly, the flow of execution is different:
do_command( stuff ) {
// This code executes when the HTTP response from the
// server returns.
... code ...
}
// This code executes immediately after the request has
// been sent.
... code ...
In other words, 'do_command' sends a request to the server and continues
processing after the block. When the response returns, the code inside
the block is executed. I don't think you can emulate this behavior with
either yield or with - they are both synchronous operations.
So I can see how your example #2 might be made to work this way, but not
#1 or #3. And I'm not convinced that #2 is really better.
More generally, the notion here is to implement a rough kind of
continuation, based on external asynchronous events. There are lots and
lots of potential use cases for code that handles asynchronous responses
to program events.
> (all of which are shorter than your JavaScript example, by the way)
>
>> But it doesn't matter, because no matter what cases I come up with,
>> someone will claim "You're just saving 2 lines of code".
>
> 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.
Lets not get confused here - I'm illustrating in Javascript code because
this is something that's easy to do in Javascript (or Lua or Perl or
whatever) but hard to do in Python.
Since I haven't actually proposed what it would look like in Python, I'm
not sure that it makes sense to argue that it doesn't "look like"
Python. That remains to be seen.
> > The fact that it saves 2 lines of code in many different places in
> > my program can't easily be illustrated in an email message.
>
> Well, this far, you haven't even been able to illustrate how your
> unspecified block syntax would have saved you a single line even in your
> three-line example. That's not a good start, really.
Lets try that one again, now that I (hopefully) have given a clearer
explanation of what I am trying to do.
>> I would disagree with one bit: I think most of those things can be done
>> in Python today, they are just complicated and ugly under the current
>> syntax. As much as people decry 'syntactic sugar', I would argue that
>> those things you mentioned (even the AST example, although it's tricky)
>> really just need sugar to make them feasible and useful to ordinary
>> programmers, rather than any fundamental change to the execution model.
>
> 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, rather than theoretically-useful-for-everything-maybe language
> constructs that's been dreamed up in some laboratory. And all the
> things I've mentioned *are* used in real code.
Well, I'm not going to give solutions for all of the examples you
raised, because (a) its off-topic, and (b) it's not necessary. But I
will take two examples from your list: The LINQ example and the
RuleDispatch example.
For the LINQ example, all I need to do is point to SQLObject, which does
something very similar - it builds an SQL query using Python
expression syntax. We could improve SQLObjects's syntax quite a bit by
allowing overloading of the 'and' and 'or' operator - right now, it has
to use '&' and '|', which have the wrong precedence and require extra
parens.
For RuleDispatch, we already know it works in Python, the only question
is how to make it easier to use. And that's been the subject of a number
of threads on this list, of which there are two parts: How to write the
dispatcher, and how to express the dispatch constrains in syntax.
Writing the dispatcher isn't a problem - I wrote one for my embedded
mini-language, Saga, in a day or two just by looking up the
Chambers/Chen paper on ACM library.
So really it all boils down to syntax.
> Also see the "Patterns are signs of weakness in programming languages"
> discussions:
>
> http://newbabe.pobox.com/~mjd/blog/prog/design-patterns.html
OK I read it - I think the author is overgeneralizing.
> and note that Python's usually aiming for "(nearly) invisible", not
> "formal", in Norvig's taxonomy.
>
> Also see the part about use cases for block constructs in my original
> post to this thread.
-- Talin
More information about the Python-3000
mailing list