
Dear All, I have an idea, though the acceptability of it is a matter for debate. It seems that this would be the appropriate place to post, but if not, or if you've already tired of this proposal, sorry. A common pattern when creating decorators is something of the form: def decorator(func): def wrapper(*args): func(modulate(args)) return wrapper This is surprisingly reminiscent of the kind of code decorators were introduced to avoid: class Example(object): def method(cls, *args): modulate(args) method = classmethod(method) The proposal is thus to introduce "@return" that returns the decorated object, a hybrid of the behavior of the return statement and decorators. I think the intended semantics are clear, providing you know the basics of how decorators work: def decorator(func): @return def wrapper(*args): func(modulate(args)) Much as the class declaration was beautified to: def Example(object): @classmethod def method(cls, *args): modulate(args) An alternative I considered, and rejected through ugliness, was allowing a funcdef in a return statement: def decorator(func): return def wrapper(*args): func(modulate(args)) The syntax of "@return" has the advantage of matching the decorator syntax, particularly beneficial given its most obvious use-case. There are uglinesses though, a simplistic reading of "@return" would imply the existence of a function called "return", and while the return statement can be used with brackets, it certainly should not be turned into a function. Also: from functools import wraps def decorator1(func): @return @wraps(func) def wrapper(*args): func(modulate(args)) def decorator2(func): @wraps(func) # Yuck! (not called, I think) @return def wrapper(*args): func(modulate(args)) Obviously, as this is currently a syntax error, there are few backward-compatibility concerns, and many forward-compatibility issues. If it were to be added, then a case might be made for allowing "@yield" "@throw" (class decorator) and (along with yield, eventually, maybe) "@continue". Does anyone have thoughts they'd like to share, or shall I return to the depths of obscurity from whence I came? Yours Conrad

On 13 Apr 2010, at 23:36 , Conrad Irwin wrote:
So now there are two completely different language elements with the exact same syntax and used in the exact same context? Strangely enough, I don't see that working too well. Trying to find a way to get anonymous functions ("full", in the defs sense) into the language would probably be a better way to pass time.

On Tue, Apr 13, 2010 at 2:36 PM, Conrad Irwin <conrad.irwin@googlemail.com> wrote:
-0.75; Zen problems I see: * Explicit is better than implicit. I for one prefer the explicit `return wrapper` and find it clearer than the proposed magical decorator. * Special cases aren't special enough to break the rules. You're allowing keyword(s) where it/they would otherwise be illegal, which (1) looks strange and (2) begs the question of why keywords couldn't be used elsewhere (e.g. def if(...): ...), [and of course, as for allowing keywords everywhere, down that path lies madness!; not that that's part of your proposal, I'm just pointing out the slippery slope.] Cheers, Chris -- http://blog.rebertia.com

On Tue, Apr 13, 2010 at 4:36 PM, Conrad Irwin <conrad.irwin@googlemail.com>wrote:
You might be interested in Michele Simionato's excellent decorator package. The above could be written: import decorator def my_decorator(func): return decorator.decorator(func, lambda: func(modulate(args))) If your pattern is very common, you could even create your own meta-decorator, like this: def args_modulator(func, modulator): return decorator.decorator(func, lambda: func(modulator(args))) It's available on PyPi: http://pypi.python.org/pypi/decorator In a nutshell, whatever part of your pattern is common, abstract out. -- Daniel Stutzbach, Ph.D. President, Stutzbach Enterprises, LLC <http://stutzbachenterprises.com>

On 04/13/2010 11:41 PM, Daniel Stutzbach wrote:
Of course, everything is more succinct when a lambda can be used instead of defining a new function; my proposal was to deal with the times when this shorthand is not available. As Masklinn suggests, perhaps it would be better to try and get full anonymous blocks into Python; though I think that that is a futile task. Naming all functions is very helpful (as anyone who has tried to analyze call stacks with more than a few anonymous functions can testify) and most uses I have for passing blocks around can be done adequately, if unstylishly, with decorators. On 04/13/2010 11:18 PM, Chris Rebert wrote:
This is indeed an issue, whatever change is needed it is clear that "@return" is something new, and probably dangerous. There are two ways (as I see it) of thinking about "@return". Firstly it may be a glorified "return" that works on the function/class defined on the next line (instead of the optional testlist on the current line). Secondly it may be as a normal decorator, with the intended intuition being that after the function definition is completed, a return is executed with the defined function (just as for a decorator). Syntactically there seems to be a minor debate to be had between creating a new keyword '@return' and allowing 'return' after an '@'. Maybe the choice of which is preferred depends on the perceived utility of the presented intuitions. In either case, it would cause less confusion to restrict an @return to by the first in the decorator list: keyword_decorator: '@' ( 'return' | 'yield' | 'throw' ) NEWLINE decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE decorators: [ keyword_decorator ] decorator+ Though this does somewhat highlight the fact that it is not a normal decorator, and perhaps an alternative syntax that makes this clearer should be considered. I am not sure I can find anything more elegant. Conrad

On Tue, Apr 13, 2010 at 7:23 PM, Conrad Irwin <conrad.irwin@googlemail.com>wrote:
Actually, I wasn't thinking clearly earlier. The correct code would be simply: @decorator.decorator def my_decorator(func, *args, **kw): return func(modulate(args)) No lamba is needed, and you can make the inside of the wrapper as complicated as you wish. -- Daniel Stutzbach, Ph.D. President, Stutzbach Enterprises, LLC <http://stutzbachenterprises.com>

On Wed, 14 Apr 2010 01:23:08 +0100 Conrad Irwin <conrad.irwin@googlemail.com> wrote:
Well, i'm not 100% sure of the point of view below, but let's take the risk ;-) (Gentle)critics welcome. As I see it, the issue you raise is more general than the precise point of a decorator's return value. It is instead deeply rooted in Python's core syntax making func/method definitions (and classes, too) somewhat different. One doesn't write: f = function(): <body> So that one cannot write neither: return function(): <body> This point (together with the unneeded 'return' in this case) also raises the need for a special inline syntax for func defs used in higher-order functions --say for programming in functional style. This a bit of a pity because Python also offers a third syntax for similar semantics with list comprehensions. As a counter-example just for reference, Lua's function defs are normal definitions, so that there are no such issues; "return function() <body>" is perfectly valid and even common; there is no need for special inline syntax. But: * An alternate pattern (function f() <body>) is available for named functions, while unnecessary (I personly never use it). * Mainly because of the useless 'return', I guess, some users still argue for a more compact anonymous pattern. Denis ________________________________ vit esse estrany ☣ spir.wikidot.com

On 04/14/2010 03:54 PM, spir ☣ wrote:
As I understand it, there is little desire to allow function definitions to appear "just anywhere" in Python. It seems to be more of an aesthetics issue than a technical problem: result = register_callback(def success(arg): print(arg) ) Could "work" (with some jiggling of the lexer), but it's not hugely pleasant to read, and it gets even worse if you want to decorate the function, or pass multiple functions. That said, I think it is significantly nicer than the decorator abuse: @register_callback def result(arg): print(arg) Concentrating on returning functions exclusively, it seems possible that return def foo(bar): baz() return def(bar): baz() return foo(bar): baz() Could all work, the last is the least ugly (I think) but also the worst in terms of answering the "where was foo defined" question. In this case, the decorator "abuse" is much less of an abuse, mainly because assigning the return value to something isn't needed: @return def foo(bar): baz() Changing things so that return isn't necessary at all would also solve the problem, and quite nicely, but I think that's a far-too-drastic change in semantics. I suppose one could create a decorator that causes the last calculation in the function to be returned, it seems a bit too much like magic though. Conrad

On 14 Apr 2010, at 18:41 , Conrad Irwin wrote
I don't believe that's true, but it is possible that people who express this desire are directed towards other languages. I can only speak for myself when I say that I'd kill for full-fledged anonymous defs (uncrippled lambdas, whatever you call them) in Python, but the desire is most definitely there.

On Wed, Apr 14, 2010 at 5:58 PM, Greg Ewing <greg.ewing@canterbury.ac.nz> wrote:
List and other comprehensions notwithstanding. :-) Cheers, Chris -- http://blog.rebertia.com

Masklinn wrote:
Limit the scope to "the core devs" and Conrad's statement is probably true :) The problem is that: 1. Whitespace is highly significant in delineating scope and separation at a statement level 2. Whitespace is largely insignificant at the expression level That means that anonymous functions that are not limited to a single expression require either: a. the introduction of significant whitespace into a particular kind of expression (ugly, breaks the back of the deliberately created statement/expression distinction noted above) or b. the introduction of a full statement syntax which isn't dependent on significant whitespace (which grossly violates There's One Obvious Way To Do It) The course most likely to bear fruit is actually for people to identify what tools they need in the functools module in order to make Python expressions Turing complete (you should be able to use functional programming tricks to attain that without needing to introduce embedded assignments). Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------

On 04/14/2010 11:52 PM, Nick Coghlan wrote:
Maybe only allow them at certain places where they can be seen as an extension to an already existing statement syntax (not to an expression syntax): foo.bar = def(egg, spam): pass return def(egg, spam): pass yield def(egg, spam): pass Anyway, if you'd introduce @return (which I'm -1 about) you'd need also to introduce @yield. -panzi

On Wed, Apr 14, 2010 at 6:07 PM, Mathias Panzenböck <grosser.meister.morti@gmx.net> wrote:
foo.bar = def(egg, spam): pass
There have been some proposals to allow dotted names and/or indexes in place of the name, so that would be written as def foo.bar(egg, spam): pass They haven't been permanently rejected, but they've been put on hold for the same reason class decorators were -- once allowed, they can't be backed out, so lets wait until we're *sure* we need them.
return def(egg, spam): pass
This is really only useful inside another function, and isn't a clear win. (Would you return the function, or the result of calling the function? Could you put () after the definition to call it? Could you use other decorators? Could you put a comma after the definition to return a tuple of the function and something?) And note that today's idiom is merely sub-optimal, not outright terrible. You can still use your own short name instead of the long one you need for an external API. def wrap(): def _(egg, spam) pass return _ -jJ

On 04/14/2010 11:07 PM, Mathias Panzenböck wrote:
There are several places a value might be used: return/yield/throw rhs of an assignment inside a function call When treating inline-functions as values, the first case is best handled by @return - the same arguments about not putting decorators on the same line as function name apply here too. I am also slightly against truly "anonymous" functions, if it doesn't fit inside a lambda, the name at least provides some compulsory documentation, and a reference point while debugging. I am of the opinion the rhs of assignment case is better handled by allowing more flexible function names: def alpha.beta(val): pass Allowing functions inside function calls is the topic for another day. Conrad

On 15 Apr 2010, at 01:33 , Conrad Irwin wrote:
Isn't that statement a bit disingenuous when considering that `for` or `with` blocks can contain arbitrary complexity and not require any kind of naming?
and a reference point while debugging.
that can be useful, but again it's not like most python source provides that.

On 04/15/2010 07:10 AM, Masklinn wrote:
The thing I fear is ending up with a stacktrace like: Traceback (most recent call last): File "a.py", line 10, in <module> event('complete') File "a.py", line 6, in event def event(*args): [callback(*args) for callback in cbs] TypeError: <anonymous>() takes no arguments (1 given) In general, it is going to take a while to find out what <anonymous> is, and where it came from, and why it has the wrong signature. Because you can't pass with/for blocks around there is little need for them to carry their documentation with them. Obviously it's not impossible, it's just not pleasant either. Conrad

On 15 Apr 2010, at 13:03 , Conrad Irwin wrote:
I understand that fear, but there is no reason why the repr for the anonymous def wouldn't include the file and line where the function was created, is there?, e.g.
TypeError: <anonymous@b.py:42>() takes no arguments (1 given)
something along those lines. Tracking those infos would be necessary for debugging anyway.

Masklinn wrote:
Probably worth putting an RFE on the tracker for that idea. Best suggestion I've seen in this thread, and I can't think of anything that would make it impossible (not necessarily *easy*, but it should be possible to come up with something). Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------

On Thu, 15 Apr 2010 00:07:57 +0200 Mathias Panzenböck <grosser.meister.morti@gmx.net> wrote:
This is more or less the same argument as what I stated in a previous post: the issue is a different, incompatible, format for func defs, compared to ordinary expression. The possible name prefixing the definition breaks the pattern. More precisely, "def" (or "function"/"method") should come just before the parameter list to allow a func def be used like any other expression. This won't change... but what about an alternative, like in Lua? Denis ________________________________ vit esse estrany ☣ spir.wikidot.com

On 04/15/2010 06:42 PM, spir ☣ wrote:
It's hard to see that an alternative syntax for scoping a block is going to be acceptable. A syntax like "@return", couple with expanding the allowable forms of the def name solve many issues. Perhaps the only remaining "missing" feature is passing functions to functions, though I think that could be done with something like a "call" block: call filter: def lt(x): return x < 2 [1,2,3,4] Which would work more elegantly if all functions had named parameters: call filter: def fun(x): return x < 2 seq=[1,2,3,4] And it might be possible to restrict the contents of the block to only be functions - somewhat reducing its functionality, but retaining the "only one way to do it". call partial(filter, seq=[1,2,3,4]): def fun(x): return x < 2 Conrad

On 04/15/2010 08:07 PM, Conrad Irwin wrote:
maybe just: filter(lt,[1,2,3,4]): def lt(x): return x < 2 or filter(lt,[1,2,3,4]) where: def lt(x): return x < 2 basically something like where in haskell. but then dis doesnt save much, just reverses the order of the statements (and possibly removes lt from the scope after filter was called). is that really enough? -panzi

On Thu, Apr 15, 2010 at 9:30 AM, Mathias Panzenböck wrote:
If you look through the archives of python-ideas, you’ll find that I’ve agitated for some version of this syntax several times. What I really want is just to be able to have one or more lines written in one order but executed in another. A where statement would do that. Another proposal I had was filter(@(x),[1,2,3,4]): return x < 2 Where “@“ meant, “function taking these parameters, to be defined in the block to follow.” Another proposal was to allow decorators to use arbitrarily complex expressions. Then one could write: @lambda f: filter(f, [1, 2, 3, 4]) def results(x): return x < 2 I’ve seen some other interesting stuff being done with the with-statement today (Ex. http://code.google.com/p/ouspg/wiki/AnonymousBlocksInPython http://pypi.python.org/pypi/withhacks ) and proposals to make “with” work more like an anonymous block in certain circumstances. Say with filtering([1, 2, 3]) as result: def overtwo(x): return x < 2 (You can actually get that to work in today’s Python using withhacks, but as the name implies, it is quite hacky, since it ends up taking apart the stack to do its magic.) My feeling is that until Python has some kind of block operator, these discussions will pop up every 6 months or so. Here’s looking forward to Fall 2010’s fruitless discussion. :-[ -- Carl M. Johnson

On Wed, Apr 14, 2010 at 4:52 PM, Nick Coghlan <ncoghlan@gmail.com> wrote:
Unless I'm mistaken, Python's lambda expressions are already Turing complete. Below is a lambda expression for calculating the factorial of a number, demonstrating that lambda expressions can use recursion: lambda n: ((lambda f, *args: f(f, *args)) ((lambda f, n: 1 if n <= 0 else n*f(f, n-1)),n)) Using a similar scheme, one could write a state machine, which is sufficient to simulate the canonical Turing machine. Of course, anyone writing a real algorithm using recursive lambda expressions deserves what they get. ;-) -- Daniel Stutzbach, Ph.D. President, Stutzbach Enterprises, LLC <http://stutzbachenterprises.com>

On Wed, 14 Apr 2010 17:41:43 +0100 Conrad Irwin <conrad.irwin@googlemail.com> wrote:
Well actually, in _many_ languages the last expression is taken as return value. (Not only Lisp & friends, also pure OO ones like Io.) Python 9000 ;-) factorial = function(n): if n <= 1: 1 else: factorial(n-1) cubes = map(numbers, function(x) x*x*x) Denis ________________________________ vit esse estrany ☣ spir.wikidot.com

On 04/14/2010 11:51 PM, spir ☣ wrote:
Also in Ruby. Anyway I think this is ugly (and violates explicit is better than implicit) and might even be dangerous because you "leek" the return value of the last statement. Basically you suddenly need to always write None (or nil) at the end of a function that should not return anything. -panzi

On 15 Apr 2010, at 00:11 , Mathias Panzenböck wrote:
and might even be dangerous because you "leek" the return value of the last statement. Basically you suddenly need to always write None (or nil) at the end of a function that should not return anything. In my experience (with languages behaving that way), that tends not to be much of an issue. Most functions and methods return values anyway, so that's the general case. And it's not like you should rely on undocumented return values.
So that objection is mostly a scare-tactic, akin to the "oh noes, significant whitespace is going to kill us all" screed coming from other communities when Python comes up.

Conrad Irwin <conrad.ir...@googlemail.com> wrote:
How is that an abuse of the decorator syntax? How is your @return syntax more clear in its intent than: from decorator import decorator @decorator def a_decorator(...): .... Is returning a function from within another function - outside of decorators - that recurring a task that we need new syntax that not only overloads existing syntax for a different use, but also disrupts the readability of a function?

On 4/13/2010 5:36 PM, Conrad Irwin wrote:
Except that a) the decorator is written once and used many times and b) there is no need for a long name within the decorator. Def w and return w would suffice. One of the motivations for decorators was the need in certain applications to repeatedly wrap long names, with the consequent tedium and ease of misspelling and diffuculty of proof-reading. Something like def some_required_to_be_long_name(): reutrn 1 some_required_to_be_long_name = wrapper(some_required_to_be_long_name). Terry Jan Reedy

On 13 Apr 2010, at 23:36 , Conrad Irwin wrote:
So now there are two completely different language elements with the exact same syntax and used in the exact same context? Strangely enough, I don't see that working too well. Trying to find a way to get anonymous functions ("full", in the defs sense) into the language would probably be a better way to pass time.

On Tue, Apr 13, 2010 at 2:36 PM, Conrad Irwin <conrad.irwin@googlemail.com> wrote:
-0.75; Zen problems I see: * Explicit is better than implicit. I for one prefer the explicit `return wrapper` and find it clearer than the proposed magical decorator. * Special cases aren't special enough to break the rules. You're allowing keyword(s) where it/they would otherwise be illegal, which (1) looks strange and (2) begs the question of why keywords couldn't be used elsewhere (e.g. def if(...): ...), [and of course, as for allowing keywords everywhere, down that path lies madness!; not that that's part of your proposal, I'm just pointing out the slippery slope.] Cheers, Chris -- http://blog.rebertia.com

On Tue, Apr 13, 2010 at 4:36 PM, Conrad Irwin <conrad.irwin@googlemail.com>wrote:
You might be interested in Michele Simionato's excellent decorator package. The above could be written: import decorator def my_decorator(func): return decorator.decorator(func, lambda: func(modulate(args))) If your pattern is very common, you could even create your own meta-decorator, like this: def args_modulator(func, modulator): return decorator.decorator(func, lambda: func(modulator(args))) It's available on PyPi: http://pypi.python.org/pypi/decorator In a nutshell, whatever part of your pattern is common, abstract out. -- Daniel Stutzbach, Ph.D. President, Stutzbach Enterprises, LLC <http://stutzbachenterprises.com>

On 04/13/2010 11:41 PM, Daniel Stutzbach wrote:
Of course, everything is more succinct when a lambda can be used instead of defining a new function; my proposal was to deal with the times when this shorthand is not available. As Masklinn suggests, perhaps it would be better to try and get full anonymous blocks into Python; though I think that that is a futile task. Naming all functions is very helpful (as anyone who has tried to analyze call stacks with more than a few anonymous functions can testify) and most uses I have for passing blocks around can be done adequately, if unstylishly, with decorators. On 04/13/2010 11:18 PM, Chris Rebert wrote:
This is indeed an issue, whatever change is needed it is clear that "@return" is something new, and probably dangerous. There are two ways (as I see it) of thinking about "@return". Firstly it may be a glorified "return" that works on the function/class defined on the next line (instead of the optional testlist on the current line). Secondly it may be as a normal decorator, with the intended intuition being that after the function definition is completed, a return is executed with the defined function (just as for a decorator). Syntactically there seems to be a minor debate to be had between creating a new keyword '@return' and allowing 'return' after an '@'. Maybe the choice of which is preferred depends on the perceived utility of the presented intuitions. In either case, it would cause less confusion to restrict an @return to by the first in the decorator list: keyword_decorator: '@' ( 'return' | 'yield' | 'throw' ) NEWLINE decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE decorators: [ keyword_decorator ] decorator+ Though this does somewhat highlight the fact that it is not a normal decorator, and perhaps an alternative syntax that makes this clearer should be considered. I am not sure I can find anything more elegant. Conrad

On Tue, Apr 13, 2010 at 7:23 PM, Conrad Irwin <conrad.irwin@googlemail.com>wrote:
Actually, I wasn't thinking clearly earlier. The correct code would be simply: @decorator.decorator def my_decorator(func, *args, **kw): return func(modulate(args)) No lamba is needed, and you can make the inside of the wrapper as complicated as you wish. -- Daniel Stutzbach, Ph.D. President, Stutzbach Enterprises, LLC <http://stutzbachenterprises.com>

On Wed, 14 Apr 2010 01:23:08 +0100 Conrad Irwin <conrad.irwin@googlemail.com> wrote:
Well, i'm not 100% sure of the point of view below, but let's take the risk ;-) (Gentle)critics welcome. As I see it, the issue you raise is more general than the precise point of a decorator's return value. It is instead deeply rooted in Python's core syntax making func/method definitions (and classes, too) somewhat different. One doesn't write: f = function(): <body> So that one cannot write neither: return function(): <body> This point (together with the unneeded 'return' in this case) also raises the need for a special inline syntax for func defs used in higher-order functions --say for programming in functional style. This a bit of a pity because Python also offers a third syntax for similar semantics with list comprehensions. As a counter-example just for reference, Lua's function defs are normal definitions, so that there are no such issues; "return function() <body>" is perfectly valid and even common; there is no need for special inline syntax. But: * An alternate pattern (function f() <body>) is available for named functions, while unnecessary (I personly never use it). * Mainly because of the useless 'return', I guess, some users still argue for a more compact anonymous pattern. Denis ________________________________ vit esse estrany ☣ spir.wikidot.com

On 04/14/2010 03:54 PM, spir ☣ wrote:
As I understand it, there is little desire to allow function definitions to appear "just anywhere" in Python. It seems to be more of an aesthetics issue than a technical problem: result = register_callback(def success(arg): print(arg) ) Could "work" (with some jiggling of the lexer), but it's not hugely pleasant to read, and it gets even worse if you want to decorate the function, or pass multiple functions. That said, I think it is significantly nicer than the decorator abuse: @register_callback def result(arg): print(arg) Concentrating on returning functions exclusively, it seems possible that return def foo(bar): baz() return def(bar): baz() return foo(bar): baz() Could all work, the last is the least ugly (I think) but also the worst in terms of answering the "where was foo defined" question. In this case, the decorator "abuse" is much less of an abuse, mainly because assigning the return value to something isn't needed: @return def foo(bar): baz() Changing things so that return isn't necessary at all would also solve the problem, and quite nicely, but I think that's a far-too-drastic change in semantics. I suppose one could create a decorator that causes the last calculation in the function to be returned, it seems a bit too much like magic though. Conrad

On 14 Apr 2010, at 18:41 , Conrad Irwin wrote
I don't believe that's true, but it is possible that people who express this desire are directed towards other languages. I can only speak for myself when I say that I'd kill for full-fledged anonymous defs (uncrippled lambdas, whatever you call them) in Python, but the desire is most definitely there.

On Wed, Apr 14, 2010 at 5:58 PM, Greg Ewing <greg.ewing@canterbury.ac.nz> wrote:
List and other comprehensions notwithstanding. :-) Cheers, Chris -- http://blog.rebertia.com

Masklinn wrote:
Limit the scope to "the core devs" and Conrad's statement is probably true :) The problem is that: 1. Whitespace is highly significant in delineating scope and separation at a statement level 2. Whitespace is largely insignificant at the expression level That means that anonymous functions that are not limited to a single expression require either: a. the introduction of significant whitespace into a particular kind of expression (ugly, breaks the back of the deliberately created statement/expression distinction noted above) or b. the introduction of a full statement syntax which isn't dependent on significant whitespace (which grossly violates There's One Obvious Way To Do It) The course most likely to bear fruit is actually for people to identify what tools they need in the functools module in order to make Python expressions Turing complete (you should be able to use functional programming tricks to attain that without needing to introduce embedded assignments). Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------

On 04/14/2010 11:52 PM, Nick Coghlan wrote:
Maybe only allow them at certain places where they can be seen as an extension to an already existing statement syntax (not to an expression syntax): foo.bar = def(egg, spam): pass return def(egg, spam): pass yield def(egg, spam): pass Anyway, if you'd introduce @return (which I'm -1 about) you'd need also to introduce @yield. -panzi

On Wed, Apr 14, 2010 at 6:07 PM, Mathias Panzenböck <grosser.meister.morti@gmx.net> wrote:
foo.bar = def(egg, spam): pass
There have been some proposals to allow dotted names and/or indexes in place of the name, so that would be written as def foo.bar(egg, spam): pass They haven't been permanently rejected, but they've been put on hold for the same reason class decorators were -- once allowed, they can't be backed out, so lets wait until we're *sure* we need them.
return def(egg, spam): pass
This is really only useful inside another function, and isn't a clear win. (Would you return the function, or the result of calling the function? Could you put () after the definition to call it? Could you use other decorators? Could you put a comma after the definition to return a tuple of the function and something?) And note that today's idiom is merely sub-optimal, not outright terrible. You can still use your own short name instead of the long one you need for an external API. def wrap(): def _(egg, spam) pass return _ -jJ

On 04/14/2010 11:07 PM, Mathias Panzenböck wrote:
There are several places a value might be used: return/yield/throw rhs of an assignment inside a function call When treating inline-functions as values, the first case is best handled by @return - the same arguments about not putting decorators on the same line as function name apply here too. I am also slightly against truly "anonymous" functions, if it doesn't fit inside a lambda, the name at least provides some compulsory documentation, and a reference point while debugging. I am of the opinion the rhs of assignment case is better handled by allowing more flexible function names: def alpha.beta(val): pass Allowing functions inside function calls is the topic for another day. Conrad

On 15 Apr 2010, at 01:33 , Conrad Irwin wrote:
Isn't that statement a bit disingenuous when considering that `for` or `with` blocks can contain arbitrary complexity and not require any kind of naming?
and a reference point while debugging.
that can be useful, but again it's not like most python source provides that.

On 04/15/2010 07:10 AM, Masklinn wrote:
The thing I fear is ending up with a stacktrace like: Traceback (most recent call last): File "a.py", line 10, in <module> event('complete') File "a.py", line 6, in event def event(*args): [callback(*args) for callback in cbs] TypeError: <anonymous>() takes no arguments (1 given) In general, it is going to take a while to find out what <anonymous> is, and where it came from, and why it has the wrong signature. Because you can't pass with/for blocks around there is little need for them to carry their documentation with them. Obviously it's not impossible, it's just not pleasant either. Conrad

On 15 Apr 2010, at 13:03 , Conrad Irwin wrote:
I understand that fear, but there is no reason why the repr for the anonymous def wouldn't include the file and line where the function was created, is there?, e.g.
TypeError: <anonymous@b.py:42>() takes no arguments (1 given)
something along those lines. Tracking those infos would be necessary for debugging anyway.

Masklinn wrote:
Probably worth putting an RFE on the tracker for that idea. Best suggestion I've seen in this thread, and I can't think of anything that would make it impossible (not necessarily *easy*, but it should be possible to come up with something). Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------

On Thu, 15 Apr 2010 00:07:57 +0200 Mathias Panzenböck <grosser.meister.morti@gmx.net> wrote:
This is more or less the same argument as what I stated in a previous post: the issue is a different, incompatible, format for func defs, compared to ordinary expression. The possible name prefixing the definition breaks the pattern. More precisely, "def" (or "function"/"method") should come just before the parameter list to allow a func def be used like any other expression. This won't change... but what about an alternative, like in Lua? Denis ________________________________ vit esse estrany ☣ spir.wikidot.com

On 04/15/2010 06:42 PM, spir ☣ wrote:
It's hard to see that an alternative syntax for scoping a block is going to be acceptable. A syntax like "@return", couple with expanding the allowable forms of the def name solve many issues. Perhaps the only remaining "missing" feature is passing functions to functions, though I think that could be done with something like a "call" block: call filter: def lt(x): return x < 2 [1,2,3,4] Which would work more elegantly if all functions had named parameters: call filter: def fun(x): return x < 2 seq=[1,2,3,4] And it might be possible to restrict the contents of the block to only be functions - somewhat reducing its functionality, but retaining the "only one way to do it". call partial(filter, seq=[1,2,3,4]): def fun(x): return x < 2 Conrad

On 04/15/2010 08:07 PM, Conrad Irwin wrote:
maybe just: filter(lt,[1,2,3,4]): def lt(x): return x < 2 or filter(lt,[1,2,3,4]) where: def lt(x): return x < 2 basically something like where in haskell. but then dis doesnt save much, just reverses the order of the statements (and possibly removes lt from the scope after filter was called). is that really enough? -panzi

On Thu, Apr 15, 2010 at 9:30 AM, Mathias Panzenböck wrote:
If you look through the archives of python-ideas, you’ll find that I’ve agitated for some version of this syntax several times. What I really want is just to be able to have one or more lines written in one order but executed in another. A where statement would do that. Another proposal I had was filter(@(x),[1,2,3,4]): return x < 2 Where “@“ meant, “function taking these parameters, to be defined in the block to follow.” Another proposal was to allow decorators to use arbitrarily complex expressions. Then one could write: @lambda f: filter(f, [1, 2, 3, 4]) def results(x): return x < 2 I’ve seen some other interesting stuff being done with the with-statement today (Ex. http://code.google.com/p/ouspg/wiki/AnonymousBlocksInPython http://pypi.python.org/pypi/withhacks ) and proposals to make “with” work more like an anonymous block in certain circumstances. Say with filtering([1, 2, 3]) as result: def overtwo(x): return x < 2 (You can actually get that to work in today’s Python using withhacks, but as the name implies, it is quite hacky, since it ends up taking apart the stack to do its magic.) My feeling is that until Python has some kind of block operator, these discussions will pop up every 6 months or so. Here’s looking forward to Fall 2010’s fruitless discussion. :-[ -- Carl M. Johnson

On Wed, Apr 14, 2010 at 4:52 PM, Nick Coghlan <ncoghlan@gmail.com> wrote:
Unless I'm mistaken, Python's lambda expressions are already Turing complete. Below is a lambda expression for calculating the factorial of a number, demonstrating that lambda expressions can use recursion: lambda n: ((lambda f, *args: f(f, *args)) ((lambda f, n: 1 if n <= 0 else n*f(f, n-1)),n)) Using a similar scheme, one could write a state machine, which is sufficient to simulate the canonical Turing machine. Of course, anyone writing a real algorithm using recursive lambda expressions deserves what they get. ;-) -- Daniel Stutzbach, Ph.D. President, Stutzbach Enterprises, LLC <http://stutzbachenterprises.com>

On Wed, 14 Apr 2010 17:41:43 +0100 Conrad Irwin <conrad.irwin@googlemail.com> wrote:
Well actually, in _many_ languages the last expression is taken as return value. (Not only Lisp & friends, also pure OO ones like Io.) Python 9000 ;-) factorial = function(n): if n <= 1: 1 else: factorial(n-1) cubes = map(numbers, function(x) x*x*x) Denis ________________________________ vit esse estrany ☣ spir.wikidot.com

On 04/14/2010 11:51 PM, spir ☣ wrote:
Also in Ruby. Anyway I think this is ugly (and violates explicit is better than implicit) and might even be dangerous because you "leek" the return value of the last statement. Basically you suddenly need to always write None (or nil) at the end of a function that should not return anything. -panzi

On 15 Apr 2010, at 00:11 , Mathias Panzenböck wrote:
and might even be dangerous because you "leek" the return value of the last statement. Basically you suddenly need to always write None (or nil) at the end of a function that should not return anything. In my experience (with languages behaving that way), that tends not to be much of an issue. Most functions and methods return values anyway, so that's the general case. And it's not like you should rely on undocumented return values.
So that objection is mostly a scare-tactic, akin to the "oh noes, significant whitespace is going to kill us all" screed coming from other communities when Python comes up.

Conrad Irwin <conrad.ir...@googlemail.com> wrote:
How is that an abuse of the decorator syntax? How is your @return syntax more clear in its intent than: from decorator import decorator @decorator def a_decorator(...): .... Is returning a function from within another function - outside of decorators - that recurring a task that we need new syntax that not only overloads existing syntax for a different use, but also disrupts the readability of a function?

On 4/13/2010 5:36 PM, Conrad Irwin wrote:
Except that a) the decorator is written once and used many times and b) there is no need for a long name within the decorator. Def w and return w would suffice. One of the motivations for decorators was the need in certain applications to repeatedly wrap long names, with the consequent tedium and ease of misspelling and diffuculty of proof-reading. Something like def some_required_to_be_long_name(): reutrn 1 some_required_to_be_long_name = wrapper(some_required_to_be_long_name). Terry Jan Reedy
participants (14)
-
alex23
-
Carl M. Johnson
-
Chris Rebert
-
Conrad Irwin
-
Daniel Stutzbach
-
Greg Ewing
-
Jim Jewett
-
Lie Ryan
-
Masklinn
-
Mathias Panzenböck
-
MRAB
-
Nick Coghlan
-
spir ☣
-
Terry Reedy