On Fri, Jan 03, 2003 at 09:05:02AM -0500, Bill Bumgarner wrote:
On Friday, Jan 3, 2003, at 00:42 US/Eastern, Gisle Aas wrote:
'anon' sounds like a great name -- unlikely to be used, shorter than 'lambda', and a heck of lot more indicative as to what is going on. 'anon' does not sound that great to me. Anon what? There is lots of anonymous stuff. Arc is going for 'fn'. I would vote for 'sub' :)
Either makes more sense than 'lambda'. I prefer 'anon' because it is a very common abbreviation for 'anonymous' and because it would have reduced the scarring during the learning of lambda calculus in CS so many years ago.
'fn' and 'sub' don't seem to be much differentiated from 'def'. 'fun' would be better than 'fn', though' because that's what lambda functions are...
Of course, you could just extend the syntax of 'def'. the 'funcdef' statement remains as now: funcdef: 'def' NAME parameters ':' suite suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT but the 'anon_funcdef' expression would be something like anon_funcdef: 'def' parameters ':' suite No new keyword needs to be introduced, and the fact that they have the same name is an even bigger encouragement to identify funcdef and anon_funcdef as working in the same way. (I don't think any of these problems are related specifically to the use of 'def' for both anonymous and named functions, but I'll use my own suggested spelling throughout the following) The first kind of problem with this is figuring out how to make the parser recognize set_callback(def (): print "I am a callback, short and stout" print "Here is my handle, here is my spout", ()) correctly (that comma could either end the first argument to set_callback(), or it could mean to not print a newline after the second print statement. Then the empty tuple could be a (rather silly) third statement of the anon_funcdef, or a second parameter to set_callback(). Lua handles this by having another token to end a function definition. This is probably not going to happen in Python. Instead, you have to find a way to recognize it based on its indentation. So the above example would presumably be interpreted as a 1-argument call to set_callback(), and you'd have to write something like set_callback(def (): print "I am a callback, short and stout" print "Here is my handle, here is my spout" , ()) to be parsed as a 2-argument call to set_callback. But there are two problems with this. First, when inside grouping characters ((), [], {}), the production of INDENT and DEDENT tokens is suppressed. So you'll need to find a way to turn it back on inside the anon_funcdef production. This is a kind of coupling that I don't think yet exists between the tokenizer and parser. (Right now, 'level' is incremented when '(', '[', or '{' is seen, and decremented when ')', ']' or '}' is seen, and INDENT/DEDENT processing is suppressed whenever 'level' is nonzero) Second, you must correctly maintain the indentation level stack in a somewhat new way. In set_callback(def (): INDENT print "I am a callback, short and stout" the INDENT is not from the level of set_callback to the level of 'print', it's from some intermediate and unspecified level to the level of the print token. So you must add machinery to specify that there's some anonymous indentation level. Then, on the DEDENT in print "Here is my handle, here is my spout" DEDENT , ()) you must produce the dedent token and pop that one level of unspecified indent. I'm not sure if this is enough to handle nested anonymous functions. For instance, are there cases of "ambiguous indentation", similer to the following, that would be interpreted wrongly with the suggested method I gave above? def(): def(): pass return 1 You must also decide whether you want to accept f(def(): pass) in which case the ) must generate a DEDENT for the corresponding anonymous INDENT. On the other hand, maybe you feel comfortable requiring f(def(): pass ) The second kind of problem is that people want to be able to write the moral equivalent of code like def f(): i=0 with_lock o.l: if o.m(): i=1 but due to the way nested scopes work, you can't write def f(): i=0 with_lock(o.l, def(): if o.m(): i=1) just like you can't write def f(): i=0 def g(): i=1 g() return i and have the value of i in the scope of f be modified by the assignment. So the rules of nested scopes would require changes to make anonymous functions useful. It seems that this also complicates some simpler uses of lambda. For instance, right now f(lambda: 1, lambda: 0) works, but f(def(): return 1, def(): return 0) doesn't. The body of the first anon_funcdef is 'return 1, def (): return 0'. You have to write f((def(): return 1), def(): return 0) or, for the sake of symmetry f((def(): return 1), (def(): return 0)) that's nearly a 50% increase in the number of characters. I suppose that the production for anon_funcdef could be changed compared to somewhat alleviate this: anon_funcdef: 'def' [parameters] ':' ( test | complex_stmt ) complex_stmt: NEWLINE INDENT stmt+ DEDENT (also let an empty parameter list be omitted) then I think you could still write f(def: 1, def: 0) since the 'test' form of anon_funcdef can be recognized when the token '1' is hit (instead of NEWLINE), and the ',' is recognized as being after the 'test' token. And, due to the shorter spelling of 'def' than 'lambda', you've even gained a few characters. But this means that a 1-liner anon_funcdef has a different syntax than a 1-liner funcdef, which is a mark against this idea. Well, sorry that this message got a bit long, but I think there are some significant issues to resolve before this (cool, imo) feature can be added to the language. Unfortunately, the difficulty implementing some of them is likely to outweigh the cool, certainly in the eyes of the people with the power to decide whether to include the feature. Jeff