Issue 34850: Syntax Warning in the real world (is 0 / is 1)
Yikes, this change is spitting out a lot of warnings on first run, and plenty in stuff that's not my code to boot. A huge number of the cases, though, seem to be "is 0" and "is 1" comparisons. Having read through the original issue I get where the SyntaxWarning is coming from, but it seems it'd be a genuine end-user experience improvement to not raise the warning on those two classic "truthy" comparisons. I understand it locks in that particular implementation detail, but it also seems unlikely that that particular optimization (int 0 and int 1 as specific memory objects) would ever make sense to NOT be including in a shipping implementation (future proof by practicality). Mostly wanted to get that out there, but for now I'm rolling back my python version rather than seeing a deluge of useless warnings. Right now, this is just a great way to drown out real warnings in noisy unhelpful ones.
On Tue, Mar 31, 2020 at 11:57 PM Philip Kahn <tigerhawkvok@gmail.com> wrote:
Yikes, this change is spitting out a lot of warnings on first run, and plenty in stuff that's not my code to boot.
A huge number of the cases, though, seem to be "is 0" and "is 1" comparisons. Having read through the original issue I get where the SyntaxWarning is coming from, but it seems it'd be a genuine end-user experience improvement to not raise the warning on those two classic "truthy" comparisons.
I understand it locks in that particular implementation detail, but it also seems unlikely that that particular optimization (int 0 and int 1 as specific memory objects) would ever make sense to NOT be including in a shipping implementation (future proof by practicality).
Mostly wanted to get that out there, but for now I'm rolling back my python version rather than seeing a deluge of useless warnings. Right now, this is just a great way to drown out real warnings in noisy unhelpful ones.
Your code is buggy. The warnings are telling you that your code is buggy, even though *at the moment* it happens to work. And the fix is simple - replace every "is 0" with "== 0", and your code will be correct. ChrisA
I understand it locks in that particular implementation detail, but it also seems unlikely that that particular optimization (int 0 and int 1 as specific memory objects) would ever make sense to NOT be including in a shipping implementation (future proof by practicality).
Do you explicitly want to differentiate between *CPython integer* 0's and 1's and floats? How about Numpy and other numeric libraries? assert 0.0 is not 0 assert 1.0 is not 1 assert numpy.ones(1, dtype=int)[0] is not 1 assert numpy.int8(1) is not 1 I think you're going to cause sneaky bugs for yourself.
On Mar 31, 2020, at 05:59, Philip Kahn <tigerhawkvok@gmail.com> wrote:
I understand it locks in that particular implementation detail, but it also seems unlikely that that particular optimization (int 0 and int 1 as specific memory objects) would ever make sense to NOT be including in a shipping implementation (future proof by practicality).
Why? As far as I know, that optimization has never been included in any release of Jython, Iron, PyPy, Brython, or Skulpt. That particular test is true in some of these implementations anyway—in Brython because of a completely different optimization (ints up to 2**53 are usually smuggled around as doubles rather than as references to objects), in PyPy because of a pessimization they added to be more bug-compatible with CPython. And in some implementations it’s true sometimes and false other times (e.g., if they merge compile-time constants but don’t intern small ints, “is 1” will be true for a value that the compiler could reduce to a constant, but false for one that had to be computed at runtime). If you’re writing code like this because you expect that all Python interpreters will always have this optimization, your code is wrong and just happens to work in some situations. Do you have code that you think actually _should_ be using is 1? Or code that you have to compile over and over (e.g., your deployment server doesn’t cache .pyc files, or you spawn new instances all the time without pre-built .pycs, or your app generates and compiles code on the fly, or …) and can’t change? If there are legitimate cases like those, I think that could definitely be a compelling argument against using SyntaxWarning here. But “the warning fired as intended and showed me a bug in my code” isn’t. And without more context, it’s hard to know which is the case here. So can you explain why this is a problem for you?
31.03.20 20:21, Andrew Barnert via Python-ideas пише:
Do you have code that you think actually _should_ be using is 1? Or code that you have to compile over and over (e.g., your deployment server doesn’t cache .pyc files, or you spawn new instances all the time without pre-built .pycs, or your app generates and compiles code on the fly, or …) and can’t change? If there are legitimate cases like those, I think that could definitely be a compelling argument against using SyntaxWarning here. But “the warning fired as intended and showed me a bug in my code” isn’t. And without more context, it’s hard to know which is the case here. So can you explain why this is a problem for you?
Twice in the last month I have been creating a PR for CPython which contains "is 1". I knew what I do. One of them was in C. I needed very fast and simple test for integers 0 and 1, so I used the C equivalent of the "is" operator (compared pointers) with objects representing Python integers 0 and 1. And more, I used private CPython singletons _PyLong_Zero and _PyLong_One. There is no guarantee that all integer 0 an 1 are represented as these singletons (even in CPython), but it was only for optimization. In worst case I would lose an optimization but still got a correct result. In second PR, I needed to determine if the optional argument with default value 1 was passed, and use fast path if it was not passed. "== 1" did not work, because 1.0 was error. It was first time when I encountered a SyntaxWarning I added myself. The workaround was simple: add a global `_ONE = 1` and use it as a default value and with the "is" operator. It would work even if 1 was not interned. In any way, this PR was rejected. Conclusion? If you know what do you do you can find a workaround. But if you use this because you do not know difference between "is" and "==" and it works for you now, the warning can save you from possible bugs and teach you something.
On 3/31/2020 7:58 PM, Serhiy Storchaka wrote:
31.03.20 20:21, Andrew Barnert via Python-ideas пише:
Do you have code that you think actually _should_ be using is 1? Or code that you have to compile over and over (e.g., your deployment server doesn’t cache .pyc files, or you spawn new instances all the time without pre-built .pycs, or your app generates and compiles code on the fly, or …) and can’t change? If there are legitimate cases like those, I think that could definitely be a compelling argument against using SyntaxWarning here. But “the warning fired as intended and showed me a bug in my code” isn’t. And without more context, it’s hard to know which is the case here. So can you explain why this is a problem for you?
Twice in the last month I have been creating a PR for CPython which contains "is 1". I knew what I do.
One of them was in C. I needed very fast and simple test for integers 0 and 1, so I used the C equivalent of the "is" operator (compared pointers) with objects representing Python integers 0 and 1. And more, I used private CPython singletons _PyLong_Zero and _PyLong_One. There is no guarantee that all integer 0 an 1 are represented as these singletons (even in CPython), but it was only for optimization. In worst case I would lose an optimization but still got a correct result.
In second PR, I needed to determine if the optional argument with default value 1 was passed, and use fast path if it was not passed. "== 1" did not work, because 1.0 was error. It was first time when I encountered a SyntaxWarning I added myself. The workaround was simple: add a global `_ONE = 1` and use it as a default value and with the "is" operator. It would work even if 1 was not interned. In any way, this PR was rejected.
Conclusion? If you know what do you do you can find a workaround. But if you use this because you do not know difference between "is" and "==" and it works for you now, the warning can save you from possible bugs and teach you something.
I think that's good reasoning. "is <integer>" will almost always be a typo or misunderstanding of what "is" actually does. "is" should really only be used to determine whether some variable is pointing to a specific object. Using singletons for e.g. default values is a case where such a test can be put to good use - just beware of certain optimizations in CPython, e.g. the interning of small integers and (some) single character strings. -- Marc-Andre Lemburg eGenix.com Professional Python Services directly from the Experts (#1, Mar 22 2020)
Python Projects, Coaching and Support ... https://www.egenix.com/ Python Product Development ... https://consulting.egenix.com/
::: We implement business ideas - efficiently in both time and costs ::: eGenix.com Software, Skills and Services GmbH Pastor-Loeh-Str.48 D-40764 Langenfeld, Germany. CEO Dipl.-Math. Marc-Andre Lemburg Registered at Amtsgericht Duesseldorf: HRB 46611 https://www.egenix.com/company/contact/ https://www.malemburg.com/
participants (6)
-
Andrew Barnert
-
Chris Angelico
-
M.-A. Lemburg
-
Nick Timkovich
-
Philip Kahn
-
Serhiy Storchaka