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:
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: [...]
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 <steve@pearwood.info> wrote:
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 19 May 2018 at 04:34, Chris Angelico <rosuav@gmail.com> wrote:
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/18 12:22, Ken Hilton wrote:
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: [...]
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 <steve@pearwood.info> wrote:
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 19 May 2018 at 04:34, Chris Angelico <rosuav@gmail.com> wrote:
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
participants (7)
-
Chris Angelico
-
Ken Hilton
-
MRAB
-
Nick Coghlan
-
Rhodri James
-
Rob Cliffe
-
Steven D'Aprano