Consider blocking heterogeneous chained comparison

Some people find this legal syntax confusing: A in B < C (It means A in B and B < C.) I feel like most code reviews would not allow this kind of code to be checked in, at least without a comment explaining what the code does. What are the motivating reasons for allowing this syntax? Is there any idiomatic code that uses it? If not, I suggest dividing the comparison operators into two groups: in, not in, is, is not and <, >, <=, >=, ==, != and then disallowing chaining of operators from both groups. For example, still allowed: A <= B <= C A in B in C disallowed: A < B in C The advantage of such a change is that there is fewer "gotcha" code. I admit that this code is rarely written, but it can come up. For example, you might write your own comparison operator and then want to see if it's working: A < B is None returns false if B is not None even if A < B returns None. Also, in my opinion, the existence is a deterrent to Python and takes away from Python's beauty as a language. The downside of such a change is that the language is more complicated. As far as implementation goes, this can be done after parsing when the AST is checked and errors are raised (from what I remember). Best, Neil

Neil Girdhar wrote:
FWIW, I totally agree. Expressions like that are extremely confusing, and it is surprising that they are valid. Real-wold usage of those is more likely to be accidental than purposeful, so it would be better if they were disallowed and treated as syntax errors. -- Steve J.

On Sun, Nov 17, 2019 at 7:45 PM Neil Girdhar <mistersheik@gmail.com> wrote:
And also allowed: A is B in C A in B is C I'm not sure these are any better than the ones you've chosen to disallow :) If you want to push for these to be disallowed, I would recommend doing it first in a linter or code quality tool. That's a completely safe way to try it out, with no language changes at all. Reject them automatically in code review, or even as a pre-commit/pre-push hook (or equivalent in your own source control system). If it's done at the syntactic level, there's absolutely no recourse, and any code anywhere that uses these chained comparisons will be suddenly broken. ChrisA

Hi Neil I'm an amateur (unpaid) research mathematician. I find the syntax
Thus I prefer then equivalently we have
A < B < C
I agree with Chris, this sort of thing is better done using a linter. That's how the gotcha
Finally, when an expression such as
Thank you, Neil, for your interesting question. I don't doubt that some people find
-- Jonathan

On Sun, Nov 17, 2019 at 12:43:55AM -0800, Neil Girdhar wrote:
Programming languages permit lots of unidiomatic code that is allowed without there being a specific motivating reason for allowing it. I doubt that any of us would ask for a motivating reason to allow this: print(print(value) or print(another_value) or third_value) or expect there to be idiomatic code that includes this: if True is (((value is True) is (True is True) is True) is True) just because the language allows it. It is a never ending task to try to prevent any unidiomatic, ugly code at the language itself, especially since what counts as "ugly" is often so subjective. Generally, we need a better reason to prohibit something than just personal preference "I don't think you should write that code". Not all code is, or needs to be, best practice. I don't recall if I've ever chained operators similar to the example you have given, but I've written lots of code that *I* don't approve of, because if I'm experimenting in the REPL who cares if I write something idiomatic or not? It works, it does what I want, it doesn't matter if it is ugly or wouldn't survive a code review. What error message could you raise that wouldn't come across as sounding like HAL from 2001 scolding the coder? "I'm sorry Dave, I'm afraid I can't allow you to do that." Better to leave this to linters, style guides, code reviews and the individual good taste of the coder.
If not, I suggest dividing the comparison operators into two groups: [...]
Still allowed: a > b < c a <= b >= c != a a in b is c is not a which are equally as hideous as your motivating example. This is adding a significant semantic complication to the language, without actually preventing what you set out to prevent: Aim: prevent the coder from abusing chained comparisons. Result: now there are two kinds of comparison operators which have nothing in common except an arbitrary division, but the coder can still abuse chained comparisons.
"Suspiciously specific example." Did you do this? Ironically, this similarly awful code would be allowed under your "two groups" proposal: a in b is None since the `in` operator is in the same group as the `is` operator. So would these: a < b == None a < b == -1 # using -1 instead of None as sentinel
Also, in my opinion, the existence is a deterrent to Python
o_O Do you have evidence of actual, real people saying words to the effect of this? "I was going to use Python, but when I saw that you can abuse chained comparisons to write ugly code, I decided against it."
and takes away from Python's beauty as a language.
*shrug* I don't know, I think that the cure in this case is worse than the disease. Yes, there are some ugly abuses of chained comparisons, but dividing comparison operators into two arbitrary groups seems even uglier to me. None is not a > b 0 != a > b I can't say that the language is improved by prohibiting the first but allowing the second. I think that the status quo has the beauty of simplicity: a <op1> b <op2> c => "a <op1> b and b <op2> c" for op1, op2 both comparison operators while your proposal has the ugliness of (unnecessary?) complexity: a <op1> b <op2> c => "a <op1> b and b <op2> c" for op1, op2 both "group 1 comparison operators", or op1, op2 both "group 2 comparison operators", or a syntax error for op1, op2 in different groups. -- Steven

Neil Girdhar wrote:
FWIW, I totally agree. Expressions like that are extremely confusing, and it is surprising that they are valid. Real-wold usage of those is more likely to be accidental than purposeful, so it would be better if they were disallowed and treated as syntax errors. -- Steve J.

On Sun, Nov 17, 2019 at 7:45 PM Neil Girdhar <mistersheik@gmail.com> wrote:
And also allowed: A is B in C A in B is C I'm not sure these are any better than the ones you've chosen to disallow :) If you want to push for these to be disallowed, I would recommend doing it first in a linter or code quality tool. That's a completely safe way to try it out, with no language changes at all. Reject them automatically in code review, or even as a pre-commit/pre-push hook (or equivalent in your own source control system). If it's done at the syntactic level, there's absolutely no recourse, and any code anywhere that uses these chained comparisons will be suddenly broken. ChrisA

Hi Neil I'm an amateur (unpaid) research mathematician. I find the syntax
Thus I prefer then equivalently we have
A < B < C
I agree with Chris, this sort of thing is better done using a linter. That's how the gotcha
Finally, when an expression such as
Thank you, Neil, for your interesting question. I don't doubt that some people find
-- Jonathan

On Sun, Nov 17, 2019 at 12:43:55AM -0800, Neil Girdhar wrote:
Programming languages permit lots of unidiomatic code that is allowed without there being a specific motivating reason for allowing it. I doubt that any of us would ask for a motivating reason to allow this: print(print(value) or print(another_value) or third_value) or expect there to be idiomatic code that includes this: if True is (((value is True) is (True is True) is True) is True) just because the language allows it. It is a never ending task to try to prevent any unidiomatic, ugly code at the language itself, especially since what counts as "ugly" is often so subjective. Generally, we need a better reason to prohibit something than just personal preference "I don't think you should write that code". Not all code is, or needs to be, best practice. I don't recall if I've ever chained operators similar to the example you have given, but I've written lots of code that *I* don't approve of, because if I'm experimenting in the REPL who cares if I write something idiomatic or not? It works, it does what I want, it doesn't matter if it is ugly or wouldn't survive a code review. What error message could you raise that wouldn't come across as sounding like HAL from 2001 scolding the coder? "I'm sorry Dave, I'm afraid I can't allow you to do that." Better to leave this to linters, style guides, code reviews and the individual good taste of the coder.
If not, I suggest dividing the comparison operators into two groups: [...]
Still allowed: a > b < c a <= b >= c != a a in b is c is not a which are equally as hideous as your motivating example. This is adding a significant semantic complication to the language, without actually preventing what you set out to prevent: Aim: prevent the coder from abusing chained comparisons. Result: now there are two kinds of comparison operators which have nothing in common except an arbitrary division, but the coder can still abuse chained comparisons.
"Suspiciously specific example." Did you do this? Ironically, this similarly awful code would be allowed under your "two groups" proposal: a in b is None since the `in` operator is in the same group as the `is` operator. So would these: a < b == None a < b == -1 # using -1 instead of None as sentinel
Also, in my opinion, the existence is a deterrent to Python
o_O Do you have evidence of actual, real people saying words to the effect of this? "I was going to use Python, but when I saw that you can abuse chained comparisons to write ugly code, I decided against it."
and takes away from Python's beauty as a language.
*shrug* I don't know, I think that the cure in this case is worse than the disease. Yes, there are some ugly abuses of chained comparisons, but dividing comparison operators into two arbitrary groups seems even uglier to me. None is not a > b 0 != a > b I can't say that the language is improved by prohibiting the first but allowing the second. I think that the status quo has the beauty of simplicity: a <op1> b <op2> c => "a <op1> b and b <op2> c" for op1, op2 both comparison operators while your proposal has the ugliness of (unnecessary?) complexity: a <op1> b <op2> c => "a <op1> b and b <op2> c" for op1, op2 both "group 1 comparison operators", or op1, op2 both "group 2 comparison operators", or a syntax error for op1, op2 in different groups. -- Steven
participants (6)
-
Chris Angelico
-
Jonathan Fine
-
Neil Girdhar
-
Stephen J. Turnbull
-
Steve Jorgensen
-
Steven D'Aprano