Skip to content

Warning for foo == "bar" or "baz" #92739

Closed as not planned
Closed as not planned

Description

@Akuli

Feature or enhancement

Emit SyntaxWarning for code like if foo == "bar" or "baz". It should be written as if foo == "bar" or foo == "baz", or perhaps if foo in ("bar", "baz"). The warning is emitted only if "bar" and "baz" here are string literals or number literals as in if foo == 1 or 2.5, but foo can be any expression. Maybe also do the same for while and assert.

Pitch

Currently there's no warning, the if statement just silently does the wrong thing. I have helped many people to learn programming in Python, and in my experience, this is a mistake that every beginner makes at some point during their learning.

In an if statement, a condition like ... or "some hard-coded string" always evaluates to a truthy value (unless the string is empty in which case the or "" can be safely removed). So in this context, or "some_string" can't really be intentional. It's an error and it shouldn't pass silently, but it does.

Alternative ideas that I thought of and rejected:

  • Adding this to a linter instead of CPython: Beginners don't know what a linter is, and many beginners don't use an IDE that runs linters in the background. Whether or not they should is a matter of opinions :)
  • The or operator raising runtime error if one of the operands is a string. Breaks correct code like return foobar or "some default value". Would also be ridiculously slow.

CPython already emits a similar warning for assert(condition, message), which asserts that a tuple of two elements is truthy.

Activity

  1. nedbat commented on May 12, 2022

    @nedbat
    Member

    I think this would be great.

  2. sweeneyde commented on May 12, 2022

    @sweeneyde
    Member

    I opened #92747

  3. serhiy-storchaka commented on May 13, 2022

    @serhiy-storchaka
    Member

    I do not think this should be added in the compiler. It will complicate the code for very tiny benefit. Such kind of mistakes are only made by beginners which learn programming. It is easy to catch when it happen the first time, and it is unimaginative that anybody make it the second time.

    In contrary, the mistake in assert(condition, message) can be made even by experience programmer if he came from other programming language, and it is difficult to catch it, because it just "works", until it should fail, but do not fail, and in otherwise correct program it never fails.

  4. Akuli commented on May 13, 2022

    @Akuli
    ContributorAuthor

    It is easy to catch when it happen the first time

    I have quite the opposite experience. I know a friend who was working on a non-trivial size program (hundreds of lines) when this happened to him for the first time. If I hadn't pointed it out in a review, the program would have behaved badly in a corner case that happens somewhat rarely. He didn't notice it himself when testing.

  5. sweeneyde commented on May 14, 2022

    @sweeneyde
    Member

    Hm, I'm sort of on the fence about this. On one hand, it is an extremely common issue on StackOverflow. This question has 1,294 questions linked to/from it including many, many duplicates.

    I do buy the argument that the best tool to detect this is a linter, and needless complexity should be avoided, but I also think this might give a bit of benefit to beginners. I would defer to those with more experience teaching beginners though. I would assume that issue would be particular to those learning Python as their first programming language.

  6. ronaldoussoren commented on May 14, 2022

    @ronaldoussoren
    Contributor

    Hm, I'm sort of on the fence about this. On one hand, it is an extremely common issue on StackOverflow. This question has 1,294 questions linked to/from it including many, many duplicates.

    I do buy the argument that the best tool to detect this is a linter, and needless complexity should be avoided, but I also think this might give a bit of benefit to beginners. I would defer to those with more experience teaching beginners though. I would assume that issue would be particular to those learning Python as their first programming language.

    IMHO The proposed warning can only find a very limited subset of possibly problematic patterns without resulting in a high level of false positives.

    The stack overflow question you link to is an example of that. That refers to "a or b or c == 2". In the context of that question it is clear that the OP should have used "a == 2 or b == 2 ...", but I've used similar code patterns where the code as written was correct.

  7. sweeneyde commented on May 14, 2022

    @sweeneyde
    Member
  8. Akuli commented on May 15, 2022

    @Akuli
    ContributorAuthor

    There seems to be 3 different opinions about this:

    1. Should be added to cpython
    2. Complicates code too much and belongs to a linter (@rhettinger)
    3. Complicates code too much and isn't useful

    For opinion 3:

    IMHO The proposed warning can only find a very limited subset of possibly problematic patterns without resulting in a high level of false positives.

    I don't see how limited implies it's useless. Beginners use more hard-coded strings and ints in their if checks than experienced users, so restricting this to hard-coded values doesn't matter very much. The list above shows this quite clearly.

    This one boils down to whether we want "simple is better than complex" or "practicality beats purity". To me, a warning like this seems very practical, while others prefer keeping the compiler simple.

  9. boxed commented on May 16, 2022

    @boxed
    Contributor

    Might I propose a much simpler option that also catches much more:

    Warn for any literal in an if surrounded by and/or/in.

  10. serhiy-storchaka commented on May 22, 2022

    @serhiy-storchaka
    Member

    #92747 adds 60 lines of the C code! It is a much even for more useful feature.

    • Core developers need to spend their time to review the initial changes.
    • Every time significant changes are made in the compiler they need to review that code to ensure that it does not require changes. Or update it.
    • Every new reader of the compiler sources will spend his time to read and comprehend these 60 lines.

    And the benefit? If a beginner who learn programming with Python as his first language will get a warning which he will not be able to understand when he makes one specific kind of 100 kinds of errors which beginners do. In any case it will end on StackOverflow or other forum, if he just not ask a teacher or a classmate.

  11. boxed commented on May 22, 2022

    @boxed
    Contributor

    The argument above can be rephrased:

    • Only 60 lines of C code
    • Those 60 lines are only read rarely by a very few core developerers
    • While both beginners and intermediate programmers make this mistake probably hundreds or thousands of times a day every day all over the world

    Python is the biggest programming language in the world. It has enormous positive benefits if it helps people, especially beginners who are already having a very hard time. This is why the new error messages in 3.11 were introduced and why they are so awesome.

    My suggestion above is probably shorter than 60 lines of C too, and would catch other mistakes too.

  12. Akuli commented on May 22, 2022

    @Akuli
    ContributorAuthor

    The problem with this is that experienced people don't understand how common this mistake is, and how much the warning would help beginners.

    will get a warning which he will not be able to understand

    This is true, but it doesn't mean that the warning is useless. It tells the beginner that they are doing something wrong. It mentions the line number of the broken line of code. It is very easy to search on google (although this isn't a big difference, as "python or not working" already finds this problem).

    one specific kind of 100 kinds of errors which beginners do

    This one is worse than other beginner problems, because you don't even realize that something is wrong. As I said, this could happen when your programs are already 300 lines long or so.

  13. Akuli commented on Jun 3, 2022

    @Akuli
    ContributorAuthor

    Maybe this warning could be compared to the new warning for is:

    >>> if x is 1: print("hi")
    ... 
    <stdin>:1: SyntaxWarning: "is" with a literal. Did you mean "=="?
    

    It's a similar problem: experienced programmers (coming from other languages or otherwise) will use == as supposed to, and not try to combine strings with or, while beginners translating their thoughts from English are more likely to use is or misuse or.

    I think the or warning is slightly less important than the is warning though. Someone could program Python for a long time and use is for all checks between integers, and their code would stop working only when it gets an integer that's too big to be cached. With or, at least your code won't appear to work when you test it, if you test it properly. I have even seen a tutorial that uses is in their first if statement example, but a badly written or would never make its way into a tutorial (although many tutorials don't warn about it).

    But still, where do we draw the line? Does this really make the is warning acceptable and the or warning a bad idea?

  14. boxed commented on Jun 3, 2022

    @boxed
    Contributor

    @Akuli just warning for any part of an if that can be trivially determined to be static at compile time seems like a much cleaner solution to the original problem.

    So if 1 would warn, if foo or 1 would warn, but also the original example if foo == "bar" or "baz".

    It's not about or, or and or is. It's about a literal as a part of what should be an evaluated expression. This btw makes sense for while too!

  15. boxed commented on Jun 3, 2022

    @boxed
    Contributor

    @oda-gitso good point. No not that. I guess literal True as the entire expression would have to be whitelisted for this warning. Makes it a bit less clean, but still ok I think.

  16. Akuli commented on Jun 3, 2022

    @Akuli
    ContributorAuthor

    I'm closing this issue, because it just doesn't seem to be going anywhere: a few core developers say no, and you generally don't go online to change your mind. In general, I'm confused about whether the core developers think that Python is supposed to be beginner-friendly: if x is 1 warning suggests yes, this issue suggests no. I did expect this to be controversial though :)

    official Python tutorial or elsewhere in the documentation

    This isn't a documentation issue. When a beginner learns to program, they have:

    • An editor that may or may not run linters
    • The Python interpreter
    • Their own debugging skills (which really can fail to find the problem)
    • A tutorial of some kind, usually not the official tutorial
    • A more experienced programmer (or several) who at least answers their questions

    We can't just update all tutorials, just because there's so many different tutorials. Same goes for editors and linters. If we want this problem to be detected reliably before the experienced programmer(s), it has to be done by the interpreter.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    interpreter-core(Objects, Python, Grammar, and Parser dirs)type-featureA feature request or enhancement

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions