[Python-ideas] Proposal for Ruby-style anonymous block functions (that don't kill the indention)

Carl Johnson carl at carlsensei.com
Mon Nov 10 09:18:09 CET 2008


On 2008/11/09, at 8:15 pm, Mike Meyer wrote:

> On Sun, 9 Nov 2008 16:56:55 -1000
> Carl Johnson <carl at carlsensei.com> wrote:
>
>> This list had a proposal last month to make everything an expression,
>> and it has not infrequent attempts to create multi-line lambdas,  
>> and I
>> think the reason for this is that people want a better way to create
>> functions that act like Ruby-style blocks since sometimes it makes
>> more sense to write the function that will be passed after the thing
>> it will be passed to and not before. So, here's my proposal. I expect
>> it to get rejected, but hey, someone approved @decorator, so maybe it
>> will make it...
>
> I think you may be on to something. You've identified the real cause
> of the reasons this kind of thing generates ugly code, and attempted
> to deal with them. But it needs some tweaking.
>
>> Instead of
>>
>>>>> def decorator(f):
>> ...     def inner(*args, **kwargs):
>> ...         print(*args, **kwargs)
>> ...         return f(*args, **kwargs)
>> ...     return inner
>> ...
>>
>> where the def inner comes before you know what it's going to be used
>> for, why not
>>
>>>>> def decorator(f):
>> ...     return @(*args, **kwargs):
>> ...         print(*args, **kwargs)
>> ...         return f(*args, **kwargs)
>> ...
>
> You seem to have realized *part* of the problem, and attempt to deal
> with it here:
>
>> Caveats: This shouldn't be allowed to work with two @s in one line.  
>> If
>> you have two of them, you should give them names ahead of time with
>> def. This also should not be allowed work inside a for-, if-, with-,
>> or while- statement's initial expression, since the indenting won't
>> work out.
>
> Yup, this makes lots of sense, and would seem to eliminate some simple
> ugly cases. But it doesn't deal with the real ugliness that comes with
> multiple things in a statement. This would look like a godsend to
> creating properties, where you need three functions that could all be
> anonymous, like so:
>
>   class Ugly(object):
>        x = property(@(self):
> 	    return self._x
> 	, @(self, value):
> 	    self._x = value
> 	, @(self), "I'm the x property"):
> 	   del self._x
>
> Except that that's the simple case, and it border on unreadable all by
> itself.
>
> Maybe @() shouldn't be allowed except for the last line in a
> multi-line statement?

Properties have already been fixed in Python 2.6+ as far as I'm  
concerned, but I don't think that should be a valid use of the @, even  
without my caveats, since it's mixing blocks around inside an  
expression. The expression should be terminated before the beginning  
of the block.

>> Also, myfunc = @(args) should be preemptively banned, since
>> def is the one right way to do it. Also you shouldn't be allowed to  
>> do
>> this to make one liners with this (as you can eg. with if- 
>> statements),
>> since that's why there's lambda.
>
> I disagree with both of these, mostly on symmetry grounds. I can
> already do:
>
>    lowerfunc = lamba word: word.lower()
>
> why should this nifty new construct not be allowed to play? Similarly,
> every statement that is followed by a block can be followed by a
> simple statement, or a list of simple statements separated by
> semicolons. Why is this one different?

Mostly on grounds of TWOOTDI. I know people already consider "x =  
lambda:" to be poor style, so I want to ban bad style preemptively  
with @.

Incidentally, does anyone know why for decorators,

@lambda x: x
def f(): pass

is a syntax error? I guess people just don't want lambda based  
decorators, for whatever reason.

> In particular, this fixes one of the properties of lambda's that
> people complain about most often: the inability to put statements in
> them. Why provide that win, only to basically make it worthless by
> forcing people it to use multiple statements? I mean, this:
>
>  newlist = sorted(words, key=lambda word, print word; word.lower())
>
> would be great, but isn't allowed because lambda is restricted to an
> expression. You fix it by giving us:
>
>  newlist = sorted(words, @(word)): print word; return word.lower()
>
> only to turn around and day "No, this block is special, and you can't
> do that here."????

I think it would look better on four lines. Maybe I'm wrong, but  
that's my intuition.


>> And using this on the declaration line of a decorator is just crazy.
>
> Why? One of the most powerful languages I know of came about because
> the designers let people do "crazy" things. Sure, using a @( construct
> for the decorator expression is sort of pointless, but what if you
> want to pass an anonymous function to a decorator. Why is:
>
>    @magicdecorator(lambda word, word.lower())
>    def function(...
>
> ok, but:
>
>    @advancedmagicdecorator(@(word)):
>        return word.lower()
>    def function(...
>
> not ok?

Ah, to be honest, I hadn't thought it through and just assumed it was  
impossible to make it work, since there would be two things needing  
indent-dedent tokens in a row. Still, isn't it a little ugly? (And  
remember, this proposal is not about adding power to Python, just  
making things more readable.)

> I kinda like it, if you can figure out how to deal with things like
> property. On the other hand, it smells a lot like lambda, which some
> people would like removed from the language...

Agreed. I fully expect the BDFL to reject this proposal, but I still  
think it's interesting to consider as a "solution" to the insolvable  
problem of multiline anonymous functions.

>    <mike
> -- 
> Mike Meyer <mwm at mired.org>		http://www.mired.org/consulting.html
> Independent Network/Unix/Perforce consultant, email for more  
> information.
>
> O< ascii ribbon campaign - stop html mail - www.asciiribbon.org
>




More information about the Python-ideas mailing list