
On 2008/11/09, at 8:15 pm, Mike Meyer wrote:
On Sun, 9 Nov 2008 16:56:55 -1000 Carl Johnson <carl@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@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