Make "is" checks on non-singleton literals errors

I regularly see learners using "is" to check for string equality and sometimes other equality. Due to optimizations, they often come away thinking it worked for them. There are no cases where if x is "foo": or if x is 4: is actually the code someone intended to write. Although this has no benefit to anyone but new learners, it also doesn't really do any harm. Mike

On Mon, Oct 8, 2012 at 12:44 PM, Mike Graham <mikegraham@gmail.com> wrote:
I think the best we can do is to make these SyntaxWarnings. I had the same thought recently and I do agree that these are common beginners mistakes that can easily hide bugs by succeeding in simple tests. -- --Guido van Rossum (python.org/~guido)

On 2012-10-08, at 21:48 , Guido van Rossum wrote:
How would the rather common pattern of using an `object` instance as a placeholder be handled? An identity test precisely expresses what is meant and desired in that case, while an equality test does not. An other one which seems to have some serious usage in the stdlib is type-testing (e.g. collections.abc, decimal or tests of exception types). Without type inference, I'm not too sure how that could be handled as syntactic warnings, and as above an identity test expresses the purpose of the code better than an equality one.

On Mon, Oct 8, 2012 at 12:59 PM, Masklinn <masklinn@masklinn.net> wrote:
It wouldn't be affected. The warning should only be emitted if either argument to 'is' is a literal number or string. Even if x could be an object instance I still don't see how it would lend meaning to "if x is 4:".
Looks like you're mistaking the proposal for "reject 'is' whenever either argument is a numeric or string value". The proposal is meant to look at the source code and only trigger if a *literal* of those types is used. -- --Guido van Rossum (python.org/~guido)

On Mon, Oct 08, 2012 at 12:48:07PM -0700, Guido van Rossum wrote:
In my experience beginners barely read error messages, let alone warnings. A SyntaxWarning might help intermediate users who have graduated beyond the stage of "my program doesn't work, please somebody fix it", but I believe that at best it will be ignored by beginners, if not actively confuse them. And I expect that most intermediate users will have already learned enough not to use "is" when then mean "==". So I'm -0 on doing anything to "fix" this. Many things in Python are potentially misleading: array = [[0]*10]*10 On the other hand, I must admit that I've been known to accidently write "if x is 0:", so perhaps the real benefit is to prevent silly brainos (like typos -- thinkos perhaps?) among more experienced coders. Perhaps I should increase my vote to +0. -- Steven

On Mon, Oct 8, 2012 at 7:03 PM, Steven D'Aprano <steve@pearwood.info> wrote:
Exactly. Pragmatically, in large code bases this occurs frequently enough to worry about it, and (unlike language warts like the aliasing problem you alluded to above) it serves no useful purpose. I have seen this particular mistake reported many times in Google's extensive Python codebase. Maybe we should do something more drastic and always create a new, unique constant whenever a literal occurs as an argument of 'is' or 'is not'? Then such code would never work, leading people to examine their code more closely. I betcha we have people who could change the bytecode compiler easily enough to do that. (I'm not seriously proposing this, except as a threat of what we could do if the SyntaxWarning is rejected. :-) -- --Guido van Rossum (python.org/~guido)

On Mon, Oct 8, 2012 at 10:14 PM, Guido van Rossum <guido@python.org> wrote:
Is this any better than making `x is 0` raise a TypeError with a message about what's wrong (as suggested by Mike Graham)? In both cases, `x is 0` is basically worthless, but at least if it raises an exception people can understand what "went wrong", because of the error message that comes with the exception. -- Devin

On Tue, Oct 9, 2012 at 2:32 PM, Devin Jeanpierre <jeanpierreda@gmail.com> wrote:
But it's not a runtime error. It should depend on whether a literal is used in the source code, not whether the argument is an int. (There are tons of situations where it makes sense to dynamically compare two objects that may happen to be ints using 'is' -- just not when it's a literal.) So I claim that it should be a message produced during compilation -- or by a lint-like tool, as others have argued. -- --Guido van Rossum (python.org/~guido)

On Tue, 09 Oct 2012 22:15:42 +0200 Georg Brandl <g.brandl@gmx.net> wrote:
But it's not dangerous to write `if x == True`, and so there isn't any point in warning. As Raymond said, this is a job for a style checker. Regards Antoine. -- Software development and contracting: http://pro.pitrou.net

On Tue, Oct 9, 2012 at 6:44 AM, Mike Graham <mikegraham@gmail.com> wrote:
Are literals guaranteed to be interned? If so, this code would make sense, if the programmer knows that x is itself an interned string. Although I guess a warning wouldn't be a problem there, as they're easily ignored/suppressed. ChrisA

On 08.10.12 22:44, Mike Graham wrote:
There are no cases where
if x is "foo":
I see such code in docutils (Doc/tools/docutils/writers/latex2e/__init__.py)
or
if x is 4:
and in tests (Lib/test/test_long.py, Lib/test/test_int.py, Lib/test/test_grammar.py, Lib/test/test_winsound.py).

On Mon, Oct 8, 2012 at 6:42 PM, Serhiy Storchaka <storchaka@gmail.com> wrote:
Thanks for finding these! I can't find this in a couple versions of Python I checked. If this code is still around, it sounds like it has a bug and should be fixed.
test_grammar.py is correct, but trivially so. It merely ensures that `1 is 1` and `1 is not 1` are proper Python syntax. As we're talking about tweaking Python's syntax rules, obviously code that tests that the grammar is the current thing would use the current thing. test_int.py and test_long.py are valid but unique, in that they rely on the behavior that no other code should implicitly rely on to test an implementation detail test_winsound.py has an `is 0` check and an `is ""` check. Both should be fixed. Thanks again, Mike

On 09.10.12 02:05, Mike Graham wrote:
I can't find this in a couple versions of Python I checked. If this code is still around, it sounds like it has a bug and should be fixed.
It's "if node.tagname is 'admonition':" line.
test_winsound.py has an `is 0` check and an `is ""` check. Both should be fixed.

On Mon, Oct 8, 2012 at 3:44 PM, Mike Graham <mikegraham@gmail.com> wrote:
+1
-- Read my blog! I depend on your acceptance of my opinion! I am interesting! http://techblog.ironfroggy.com/ Follow me if you're into that sort of thing: http://www.twitter.com/ironfroggy

On Mon, Oct 8, 2012 at 12:44 PM, Mike Graham <mikegraham@gmail.com> wrote:
I think the best we can do is to make these SyntaxWarnings. I had the same thought recently and I do agree that these are common beginners mistakes that can easily hide bugs by succeeding in simple tests. -- --Guido van Rossum (python.org/~guido)

On 2012-10-08, at 21:48 , Guido van Rossum wrote:
How would the rather common pattern of using an `object` instance as a placeholder be handled? An identity test precisely expresses what is meant and desired in that case, while an equality test does not. An other one which seems to have some serious usage in the stdlib is type-testing (e.g. collections.abc, decimal or tests of exception types). Without type inference, I'm not too sure how that could be handled as syntactic warnings, and as above an identity test expresses the purpose of the code better than an equality one.

On Mon, Oct 8, 2012 at 12:59 PM, Masklinn <masklinn@masklinn.net> wrote:
It wouldn't be affected. The warning should only be emitted if either argument to 'is' is a literal number or string. Even if x could be an object instance I still don't see how it would lend meaning to "if x is 4:".
Looks like you're mistaking the proposal for "reject 'is' whenever either argument is a numeric or string value". The proposal is meant to look at the source code and only trigger if a *literal* of those types is used. -- --Guido van Rossum (python.org/~guido)

On Mon, Oct 08, 2012 at 12:48:07PM -0700, Guido van Rossum wrote:
In my experience beginners barely read error messages, let alone warnings. A SyntaxWarning might help intermediate users who have graduated beyond the stage of "my program doesn't work, please somebody fix it", but I believe that at best it will be ignored by beginners, if not actively confuse them. And I expect that most intermediate users will have already learned enough not to use "is" when then mean "==". So I'm -0 on doing anything to "fix" this. Many things in Python are potentially misleading: array = [[0]*10]*10 On the other hand, I must admit that I've been known to accidently write "if x is 0:", so perhaps the real benefit is to prevent silly brainos (like typos -- thinkos perhaps?) among more experienced coders. Perhaps I should increase my vote to +0. -- Steven

On Mon, Oct 8, 2012 at 7:03 PM, Steven D'Aprano <steve@pearwood.info> wrote:
Exactly. Pragmatically, in large code bases this occurs frequently enough to worry about it, and (unlike language warts like the aliasing problem you alluded to above) it serves no useful purpose. I have seen this particular mistake reported many times in Google's extensive Python codebase. Maybe we should do something more drastic and always create a new, unique constant whenever a literal occurs as an argument of 'is' or 'is not'? Then such code would never work, leading people to examine their code more closely. I betcha we have people who could change the bytecode compiler easily enough to do that. (I'm not seriously proposing this, except as a threat of what we could do if the SyntaxWarning is rejected. :-) -- --Guido van Rossum (python.org/~guido)

On Mon, Oct 8, 2012 at 10:14 PM, Guido van Rossum <guido@python.org> wrote:
Is this any better than making `x is 0` raise a TypeError with a message about what's wrong (as suggested by Mike Graham)? In both cases, `x is 0` is basically worthless, but at least if it raises an exception people can understand what "went wrong", because of the error message that comes with the exception. -- Devin

On Tue, Oct 9, 2012 at 2:32 PM, Devin Jeanpierre <jeanpierreda@gmail.com> wrote:
But it's not a runtime error. It should depend on whether a literal is used in the source code, not whether the argument is an int. (There are tons of situations where it makes sense to dynamically compare two objects that may happen to be ints using 'is' -- just not when it's a literal.) So I claim that it should be a message produced during compilation -- or by a lint-like tool, as others have argued. -- --Guido van Rossum (python.org/~guido)

On Tue, 09 Oct 2012 22:15:42 +0200 Georg Brandl <g.brandl@gmx.net> wrote:
But it's not dangerous to write `if x == True`, and so there isn't any point in warning. As Raymond said, this is a job for a style checker. Regards Antoine. -- Software development and contracting: http://pro.pitrou.net

On Tue, Oct 9, 2012 at 6:44 AM, Mike Graham <mikegraham@gmail.com> wrote:
Are literals guaranteed to be interned? If so, this code would make sense, if the programmer knows that x is itself an interned string. Although I guess a warning wouldn't be a problem there, as they're easily ignored/suppressed. ChrisA

On 08.10.12 22:44, Mike Graham wrote:
There are no cases where
if x is "foo":
I see such code in docutils (Doc/tools/docutils/writers/latex2e/__init__.py)
or
if x is 4:
and in tests (Lib/test/test_long.py, Lib/test/test_int.py, Lib/test/test_grammar.py, Lib/test/test_winsound.py).

On Mon, Oct 8, 2012 at 6:42 PM, Serhiy Storchaka <storchaka@gmail.com> wrote:
Thanks for finding these! I can't find this in a couple versions of Python I checked. If this code is still around, it sounds like it has a bug and should be fixed.
test_grammar.py is correct, but trivially so. It merely ensures that `1 is 1` and `1 is not 1` are proper Python syntax. As we're talking about tweaking Python's syntax rules, obviously code that tests that the grammar is the current thing would use the current thing. test_int.py and test_long.py are valid but unique, in that they rely on the behavior that no other code should implicitly rely on to test an implementation detail test_winsound.py has an `is 0` check and an `is ""` check. Both should be fixed. Thanks again, Mike

On 09.10.12 02:05, Mike Graham wrote:
I can't find this in a couple versions of Python I checked. If this code is still around, it sounds like it has a bug and should be fixed.
It's "if node.tagname is 'admonition':" line.
test_winsound.py has an `is 0` check and an `is ""` check. Both should be fixed.

On Mon, Oct 8, 2012 at 3:44 PM, Mike Graham <mikegraham@gmail.com> wrote:
+1
-- Read my blog! I depend on your acceptance of my opinion! I am interesting! http://techblog.ironfroggy.com/ Follow me if you're into that sort of thing: http://www.twitter.com/ironfroggy
participants (14)
-
Antoine Pitrou
-
Arnaud Delobelle
-
Barry Warsaw
-
Calvin Spealman
-
Chris Angelico
-
Devin Jeanpierre
-
Georg Brandl
-
Guido van Rossum
-
Joshua Landau
-
Masklinn
-
Mike Graham
-
Raymond Hettinger
-
Serhiy Storchaka
-
Steven D'Aprano