Make keywords KEYwords only in places they would have syntactical meaning
Hi all, Yes, this is another idea for avoiding breaking existing code when introducing new keywords. I'm not sure if this is too similar to Guido's previous "allow keywords in certain places" idea, but here goes: Only treat keywords as having any special meaning when they are in places with syntactical significance. So, currently, let's say someone set the variable "and_" to some value. The following lines are both SyntaxErrors: True and_ False obj.and = value And the following are both correct: True and False obj.and_ = value My idea is to only treat keywords as having special meaning when they're in the right place. So the following would all be legal: >>> from operator import and >>> var = and(True, False) >>> var False >>> var = True and False >>> var False >>> def except(exc, def): ... try: ... return def() ... except exc as e: ... return e ... >>> except(ZeroDivisionError, lambda: 1/0) ZeroDivisionError('division by zero',) >>> except(ZeroDivisionError, lambda: 0/1) 0.0 >>> import asyncio as await #this is already currently legal, but will not be in the __future__ >>> async def async(def): ... return await await.get_event_loop().run_in_executor(None, def) ... >>> And so on. What are your thoughts? Sharing, Ken Hilton ;
On 18/05/18 12:22, Ken Hilton wrote:
My idea is to only treat keywords as having special meaning when they're in the right place. So the following would all be legal:
>>> from operator import and >>> var = and(True, False) >>> var False >>> var = True and False >>> var False >>> def except(exc, def): ... try: ... return def() ... except exc as e: ... return e ... >>> except(ZeroDivisionError, lambda: 1/0) ZeroDivisionError('division by zero',) >>> except(ZeroDivisionError, lambda: 0/1) 0.0 >>> import asyncio as await #this is already currently legal, but will not be in the __future__ >>> async def async(def): ... return await await.get_event_loop().run_in_executor(None, def) ... >>>
And so on.
What are your thoughts?
I asked about this earlier, much less clearly, and didn't get a helpful answer. I haven't had the spare time to look at the parser since then to see if it's plausible. Though seriously, your example with "except()" makes me want to recant! -- Rhodri James *-* Kynesim Ltd
On Fri, May 18, 2018 at 07:22:13PM +0800, Ken Hilton wrote: [...]
Only treat keywords as having any special meaning when they are in places with syntactical significance. [...] My idea is to only treat keywords as having special meaning when they're in the right place.
Chris discussed his experience with REXX, which works like that: The problem is that you can go a long way down the road of using a particular name, only to find that suddenly you can't use it in some particular context. [...] So the question is: Is it better to be able to use a keyword as an identifier for a while, and then run into trouble later, or would you prefer to be told straight away "no, sorry, pick a different name"? https://mail.python.org/pipermail/python-ideas/2018-May/050694.html I think its a no-brainer: I'd much rather get an error earlier, when I first decide its a good idea to call a method "while", rather than six months later when I stumble across a corner case that stops me from using it. I'm sure that everyone is absolutely champing at the bit to write code like: for = if if while else else or = [in or for for in in for if if] *wink* but I think we should be conservative about allowing keywords as identifiers. Requiring a clear and obvious escaping mechanism (verbatim strings \name) or a clear and obvious renaming convension (name_) is better than a context-sensitive grammar. That's even assuming such a context-sensitive grammar would be possible within the requirement that Python's parser is LL(1). -- Steve
On Fri, May 18, 2018 at 9:59 PM, Steven D'Aprano
That's even assuming such a context-sensitive grammar would be possible within the requirement that Python's parser is LL(1).
I'm sure it could be done, but it may impact existing Python grammar. So backward compatibility might mean making certain words "keywords" in contexts where they otherwise wouldn't be, and then just throwing SyntaxError because it would have been ambiguous. But even if it's possible, I don't think it's desirable. ChrisA
On 2018-05-18 12:22, Ken Hilton wrote:
Hi all,
Yes, this is another idea for avoiding breaking existing code when introducing new keywords. I'm not sure if this is too similar to Guido's previous "allow keywords in certain places" idea, but here goes:
Only treat keywords as having any special meaning when they are in places with syntactical significance. So, currently, let's say someone set the variable "and_" to some value. The following lines are both SyntaxErrors:
True and_ False obj.and = value
And the following are both correct:
True and False obj.and_ = value
My idea is to only treat keywords as having special meaning when they're in the right place. So the following would all be legal:
>>> from operator import and >>> var = and(True, False) >>> var False >>> var = True and False >>> var False >>> def except(exc, def): ... try: ... return def() ... except exc as e: ... return e ... >>> except(ZeroDivisionError, lambda: 1/0) ZeroDivisionError('division by zero',) >>> except(ZeroDivisionError, lambda: 0/1) 0.0 >>> import asyncio as await #this is already currently legal, but will not be in the __future__ >>> async def async(def): ... return await await.get_event_loop().run_in_executor(None, def) ... >>>
And so on.
What are your thoughts?
This would be legal, but what would happen? def yield(x): print('YIELD') def foo(): yield('FOO') f = foo()
On Sat, May 19, 2018 at 2:56 AM, MRAB
On 2018-05-18 12:22, Ken Hilton wrote:
Hi all,
Yes, this is another idea for avoiding breaking existing code when introducing new keywords. I'm not sure if this is too similar to Guido's previous "allow keywords in certain places" idea, but here goes:
Only treat keywords as having any special meaning when they are in places with syntactical significance. So, currently, let's say someone set the variable "and_" to some value. The following lines are both SyntaxErrors:
True and_ False obj.and = value
And the following are both correct:
True and False obj.and_ = value
My idea is to only treat keywords as having special meaning when they're in the right place. So the following would all be legal:
>>> from operator import and >>> var = and(True, False) >>> var False >>> var = True and False >>> var False >>> def except(exc, def): ... try: ... return def() ... except exc as e: ... return e ... >>> except(ZeroDivisionError, lambda: 1/0) ZeroDivisionError('division by zero',) >>> except(ZeroDivisionError, lambda: 0/1) 0.0 >>> import asyncio as await #this is already currently legal, but will not be in the __future__ >>> async def async(def): ... return await await.get_event_loop().run_in_executor(None, def) ... >>>
And so on.
What are your thoughts?
This would be legal, but what would happen?
def yield(x): print('YIELD')
def foo(): yield('FOO')
f = foo()
"yield" would have to be a keyword in any context where an expression is valid. Which, in turn, makes it utterly useless as a function name, or any other identifier. ChrisA
On 19 May 2018 at 04:34, Chris Angelico
"yield" would have to be a keyword in any context where an expression is valid. Which, in turn, makes it utterly useless as a function name, or any other identifier.
Right, I spent a fair bit of time thinking about this in the context of using "given" to introduce postfix assignment expressions, and while it's reasonably straightforward to make it so that keywords that can't start an expression or statement (currently "as", "in", "is", "and", "or") can also be used as names, we don't have that kind of freedom for keywords that can *start* an expression or statement ("async"/"await" relied on some parser tricks that relied on the fact that "async" always needed to be paired with "def" to introduce a coroutine, and "await EXPR" was only permitted inside coroutine definitions). We also run into the problem that even when the compiler can tell the difference, *humans* are still likely to be confused by the potential ambiguity (for the same reason that shadowing builtins is generally considered poor style). Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia
On 18/05/2018 12:22, Ken Hilton wrote:
Hi all,
Yes, this is another idea for avoiding breaking existing code when introducing new keywords. I'm not sure if this is too similar to Guido's previous "allow keywords in certain places" idea, but here goes:
Only treat keywords as having any special meaning when they are in places with syntactical significance. So, currently, let's say someone set the variable "and_" to some value. The following lines are both SyntaxErrors:
True and_ False obj.and = value
And the following are both correct:
True and False obj.and_ = value
My idea is to only treat keywords as having special meaning when they're in the right place. So the following would all be legal:
>>> from operator import and >>> var = and(True, False) >>> var False >>> var = True and False >>> var False >>> def except(exc, def): ... try: ... return def() ... except exc as e: ... return e ... >>> except(ZeroDivisionError, lambda: 1/0) ZeroDivisionError('division by zero',) >>> except(ZeroDivisionError, lambda: 0/1) 0.0 >>> import asyncio as await #this is already currently legal, but will not be in the __future__ >>> async def async(def): ... return await await.get_event_loop().run_in_executor(None, def) ... >>>
And so on.
What are your thoughts?
Sharing,
Ken Hilton ;
Great idea, but why restrict it to keywords? Why not also allow operators to be variable names:
+ = 23 + + + + + 69 - = 21 - - -21 There would be some minor ambiguities, e.g. would - - - - evaluate to (- -) - (-) # -42 or (-) - (- -) # +42 or - ( - ( - ( - ))) # -21 or - (- - -) # 0 and indeed + + + + + could *in theory* evaluate to + ( + ( + ( + ( +)))) # 23 or (++) + (++) # 46 but I'm sure we could formulate some sensible rules to always get the intended meaning. :-)
Rob Cliffe
participants (7)
-
Chris Angelico
-
Ken Hilton
-
MRAB
-
Nick Coghlan
-
Rhodri James
-
Rob Cliffe
-
Steven D'Aprano