0

I got a headscratcher: someone submitted code to test whether all of some checkboxes were unchecked, and it indicated True when an even number were checked. The code looked something like:

if (box1.checked == box2.checked == box3.checked == box4.checked == box5.checked == false) ...

and I read it naively as: if each one is false... But this was incorrect. I figured out why (C# evaluates from left to right, and the result of a boolean compare is a boolean: false == false evaluates to true), but I wondered if this shows up often, and has a name? I guess I would name it Chained Falsehood or maybe False Decay as it would be fine if all operands were True.

The same idea works fine with assignment, so I can see why the coder tried it this way.

Ok, based on comments, this should not be called an anti-pattern because it is a bug. I think it should be called an idiom from another language. But vanity of vanities, thy name is Python, and its name should be called Haddock's Ayes.

27
  • 4
    This is my first time seeing something like this. I don't think it's a pattern. Maybe just call it an "anti"? :)
    – Samuel
    Commented Sep 27, 2017 at 18:57
  • 3
    seems like a bug more than a pattern
    – yitzih
    Commented Sep 27, 2017 at 19:55
  • 2
    I don't think the criteria for a pattern (or anti-pattern) is as simple as "more than one person does it". A pattern is more of an established practice for solving a particular type of problem. Just because a few people use it here or there doesn't mean it rises to the level of pattern. We would have millions of patterns if that were the case.
    – Eric King
    Commented Sep 27, 2017 at 20:01
  • 4
    @Newtopian It's definitely not a bug in C# except perhaps not warning against/disallowing it. In my opinion, Python's support for this is a misfeature. If nothing else, Python is clearly the outlier here. (In math, there's usually a distinction between propositions and the objects of the language so x = y = z is unambiguous, as (x = y) = z is not even syntactically correct. If we were talking about = as a Boolean operation, i.e. <->, then x <-> y <-> z would behave like the C# if <-> had the appropriate associativity, but it is clearest for it to be non-associative.) Commented Sep 27, 2017 at 21:13
  • 4
    How about The Boolean Centipede in reference to imdb.com/title/tt1467304
    – Newtopian
    Commented Sep 27, 2017 at 21:42

5 Answers 5

10

This is just a coding error due to someone's misunderstanding. I don't know why you think it should have a name. It's definitely not an anti-pattern. An anti-pattern describes a common architectural pattern that negatively impacts maintainability, not a coding error.

I don't know how common this is, but I expect it to be rather rare in any professional context even from junior programmers. I can see it being more common in some introductory programming classes, but it should quickly be discovered to be incorrect. First, the students won't be taught this. Second, even the most cursory of testing will reveal that it doesn't work. Third, the most obvious way of doing this is simpler, namely !box1.checked && !box2.checked && ... && !boxN.checked.

If you are working in a professional context (and arguably even in a non-professional context), the real problem is a process anti-pattern where people are submitting untested code.

12
  • 2
    @nocomprende: Still doesn't have a name. Call it "bad coding." Commented Sep 27, 2017 at 20:17
  • 2
    @nocomprende: This isn't off-by-one; it's just bad coding. You can code badly an almost unlimited number of ways; doesn't mean each way deserves a name. Commented Sep 27, 2017 at 20:21
  • 4
    @nocomprende: Further, I think the current generation of programmers' obsession with naming things is actively harmful to our profession. Using arbitrary vocabulary gives the false impression that the people using said vocabulary understand things that they actually do not understand. Commented Sep 27, 2017 at 20:28
  • 2
    @nocomprende Except for cache invalidation. Commented Sep 28, 2017 at 1:16
  • 2
    @RobertHarvey That's so true. Dependency Injection was something a lot of people, including myself, were using even before it had a name. When the term popped up everywhere, it left a lot of people scratching heads trying to understand what was so special there. And worse - a few newbies that didn't grasp the concept but liked the fancy name put their hands on some weird API and ended up writing some horrendous pieces of Injection Hell.
    – T. Sar
    Commented Sep 28, 2017 at 11:14
4

It's not an anti-pattern. To be an anti-pattern, it would first have to be a pattern. Which means it would have to be a common solution to a problem to be a pattern, and a bad common solution to be an anti-pattern. But this is not a common solution to anything.

I'd say it is a WTF. WTF is obviously an abbreviation. You may assume that it means "Worse Than Failure". Or you may assume it means something else.

I have once in my life had to check that at least two of three conditions are true, so I counted how many were true. If I actually needed to do what the code here does (not what it was likely intended to do), I'd write

int falseCount = (box1.checked ? 0 : 1) + (box2.checked ? 0 : 1) etc.
if (falseCount % 2 == 1) { ... }
3
  • 1
    Wouldn't this check if exactly an odd number of boxes were checked? This seems different from what your paragraph is talking about which I would render as falseCount >= 2. Commented Sep 27, 2017 at 23:02
  • Maybe it is an anti-dark-pattern? Maybe 95% of all code is not visible?
    – user251748
    Commented Sep 28, 2017 at 0:38
  • I like the idea of WTF!
    – T. Sar
    Commented Sep 28, 2017 at 14:33
3

I see this every now and then, not on this exact form but in the more general form of "a line of code doing a lot of things".

It could be a pattern if common and misguided ways for trying to achieve premature optimization or to make you look smart qualified as patterns (I am not really sure if they do) and it had a concise name. In that case it would be an antipattern because:

  • Premature optimization and looking smart should not be amongst your concerns.
  • More often than not it does not buy you any actual optimization (does not really solve this problem).
  • Makes you look less smart (does not solve this problem either).
  • Makes easier to make mistakes and introduce bugs (just like in your example).
  • Obfuscates your intent.
  • Makes your code harder to debug.
6
  • If I wrote x = y = z = 5; that would make perfect sense, and probably work in most languages, wouldn't it? x == y == z == false does not work, because the pairs of false == false become true. The false values make it fail where all trues would succeed. They might have done it to look smart, not sure. I don't think it had to do with optimization. It doesn't obfuscate the intent at all, if anything the intent is more clear than the correct formulations, especially because those use negation.
    – user251748
    Commented Sep 27, 2017 at 20:39
  • 1
    @nocomprende Intent being clear is meaningless when the code is wrong
    – mmathis
    Commented Sep 27, 2017 at 21:04
  • @mmathis now if we could just create a language where clear intent produced correct code...
    – user251748
    Commented Sep 27, 2017 at 21:28
  • 1
    @nocomprende I find it hard to read and somewhat obfuscated even if I am used to python. Anyway at this point I am confused about what "this" refers to in "I wondered if this shows up often". Chained comparison? Getting the semantics wrong? Using python idioms in c#? I stand by my claims but it looks like I missed the point of the question. Commented Sep 27, 2017 at 21:41
  • 1
    @nocomprende: I see what you mean when you say that the intent is more clear; but you're missing something: how would this notation meaningfully be able to differ between && (all of them need to be false) and || (one of them must be false)? The absence of this distinction should reveal that the intent is incomplete.
    – Flater
    Commented Sep 28, 2017 at 15:43
1

I am going to disagree with the other answers here and say this is an anti-pattern as there is a pattern in use. That pattern is using equality to test booleans, rather than using logical operators. eg using if (b == true), rather than if (b). A common excuse offered for using this (anti)pattern is that ! is hard to read, so those folk write if (b == false) rather than if (!b) and then use == true for consistency.

This question neatly highlights the dangers with that pattern though. Using logical operators results in code working as expected, so this is an opportunity to educate folk in the idiomatic use of those logical operators:

// this code works as expected, unlike using ==
if (!(box1.checked || box2.checked || box3.checked || box4.checked || box5.checked)) ...
5
  • What you just did was isolate each part of the Boolean expression--which is the correct thing to do. In essence you now have 5 separate boxX.checked expressions ORed together instead of one like in the OP. I agree that using box1.checked is easier to read than box1.checked == true, but if each expression were written with the longer form, then your answer would essentially be the same. Just more verbose. Commented Sep 28, 2017 at 12:10
  • 1
    What is really fun is when someone inverts the condition to make it more understandable, which is fine, then has an empty Then body and puts the code in an Else body. So amusing.
    – user251748
    Commented Sep 28, 2017 at 12:14
  • I do also find b == true/false unpleasant and common, but this is focusing on a side issue. If the original code was instead checking if all boxes had the same checked state (i.e. all checked or all unchecked), the original author of the code would presumably have written the same thing except omitting the == false at the end. It's completely reasonable to use == to test the equality of Booleans in that case, but, of course, this still can't be written as x == y == z. Commented Sep 28, 2017 at 12:21
  • 1
    I'm not sure if using equality to test booleans is a pattern os just coding style. Patterns usually don't apply to single lines of code, they are somewhat more complex constructs that try to solve a problem. Arguing that this is a pattern open doors for claiming that "using guard conditions" is a pattern, too. I'm not sure they are, but I look at them just as good practices, not a high-level problem solving structure.
    – T. Sar
    Commented Sep 28, 2017 at 14:37
  • @T.Sar yeah, I decided to change from 'pattern' to 'idiom'. This is indeed an idiom (or at least good code) in Python. Careful where you give that thumb-circle OK sign, eh?
    – user251748
    Commented Sep 28, 2017 at 16:19
-1

There are reasons why it is considered good practice to separate both assignments and Boolean expressions. The number of surprises you can get from implicit converts (if the language supports that) and such increase with each segment in the chain.

This is the first time I've seen a Boolean chain, and hopefully it is the last. I would consider a special case of "chained assignment", which you can find a lot of conversation about it when you search.

More often than not, chained assignments have unexpected side-effects. Most code style guidelines I've seen recommend avoiding them completely.

Since there needs to be multiple instances of anything to be called a pattern, I'd say this type of thing fails that threshold. However it does win a gold star for creative bug writing.

10
  • 6
    There are no assignments, chained or unchained, in the question. Commented Sep 27, 2017 at 19:24
  • @Goyo, The same problems with chained assignments are affecting this problem. There is an implicit assignment to the if statement at the end of this. Like I said a special case of a well known problem. Commented Sep 27, 2017 at 20:13
  • 1
    @BerinLoritsch What are you talking about? I don't even know what you mean by an "assignment to the if statement" implicit or otherwise. It's possible that even at the level of assembly literally nothing gets updated other than the instruction pointer, so I'm not sure what you believe is being implicitly assigned to. Commented Sep 27, 2017 at 20:35
  • x = y = z = 5 would work. I have not seen cases where that is problematic. But when you start throwing Booleans around, false values do strange things. (True values, of course, do not. It is like odd and even numbers, or primes and composite numbers. The world is just weird.)
    – user251748
    Commented Sep 27, 2017 at 20:41
  • 1
    @Newtopian so what's a few = signs between friends?
    – user251748
    Commented Sep 27, 2017 at 21:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.