This is a minor pet peeve of mine that I felt like sharing. Feel free to post a comment if you agree, disagree or have your own pet coding peeve to share with other readers of this blog.

I quite often see .NET code that tests for the value of a Boolean to see whether it's true or false:

if (booleanVariable == true)

{

  …

}

or

If isBooleanFunction() = False Then

  …

End If

Now while not strictly incorrect, this style is, at least, redundant: a Boolean is by nature true or false, and testing for equality with another Boolean returns a Boolean.

I personally prefer to use this:

if (booleanVariable)

{

  …

}

or

If Not(isBooleanFunction()) Then

  …

End If

Now I'm fully aware I'm taking a purist's perspective on this: when you take a look at the underlying IL created by Visual Studio (something you can do very easily with .NET Reflector 6) there is absolutely no difference in the generated code – the additional test is optimized out - but even if there's no impact from an efficiency perspective (and the additional source code bytes don't eat up a huge amount of hard-drive capacity) it just feels inelegant. Sorry.

There are interesting historical reasons for explicit testing, though, which I'd like to mention. Back before C++ had a native Boolean data-type – and this is still true of C – Booleans were represented as integers which would usually be generated by a pre-processor symbol (such as via Win32's TRUE and FALSE) or by an enumeration (such as ObjectARX's Adesk::kTrue and kFalse). So you would have to test for equality explicitly:

if (booleanVariable == Adesk::kTrue)

{

  …

}

As C's (and therefore C++'s – but not C#'s) if statement checks for whether the expression passed in is non-zero, it's in practice probably just fine not to care about the comparison with Adesk::True, but that would make a potentially dangerous assumption about the values of true and false, which isn't a good idea (things can change, as we'll see below :-). C# is different: if you try to pass a numeric expression into an if statement the compiler will ask for a Boolean, as that's the appropriate native type.

So is truth relative or absolute? Here's an interesting language quirk that can occasional cause the odd, subtle error: most modern languages who provide the concept of mapping Booleans to integers – perhaps because that's what they use to implement them - work on the principle that false is 0 and true is non-zero, usually defaulting to 1. Visual Basic (prior to .NET) was different (and presumably this is still true of VBA): false was indeed 0 but the default value for true was –1. This quirk was rationalised out at the introduction of VB.NET, but still causes the odd migration problem if code makes the mistake of depending on absolute truth. 🙂

Another interesting aside, as you will sometimes come across code like this… when I was writing C++ code regularly, I'd often invert the sides of the equality test to avoid a subtle class of error (this is a technique I learned from a colleague many years ago):

if (Adesk::kTrue == booleanVariable)

{

  …

}

The reason for the inversion is that if you happen to omit one of the equals signs (which is quite a common typo to make, especially if you also code in languages that use a single equals sign for testing equality), the C++ compiler will at least tell you there's an error, as you're attempting to assign to an r-value (which comes from the fact it typically belongs to the right side of an equation rather than the left… l-values are assignable but not r-values). So as a force of habit I would start with the value we're checking against, to avoid this problem.

It turns out there's less risk of hitting this kind of issue if you're coding in C#, at least (I haven't checked modern C++ compilers), at least here you get a helpful warning message:

A helpful warning message 

Alright, that's it for today. Thanks for indulging my little rant and please do post a comment if you have something to add.

19 responses to “Testing truth”

  1. We have to routinely contend with that issue with C++ ActiveX programming (VARIANT_BOOL), which was for some strange reason, carried into Visual LISP (:VLAX-TRUE/FALSE), in spite of the fact that VBA's If() doesn't require an explicit test.

    For example:


    Command: (if :vlax-false "True" "False")
    "True"

  2. J. Daniel Smith Avatar

    "if (booleanVariable == true)" (really) bugs me too.

    At /W4, the VS C++ compiler will issue an "assignment in conditional expression" warning, so there's much less need for the old "if (Adesk::kTrue == booleanVariable)" habit. (You ARE compiling at /W4, right?)

  3. Yea, but it's not nearly as bad as the classic 'double-negative' LISP: (if (not (null something))...) verses (if something ...)

  4. I agree with you on using 'if (booleanVariable)' as it is straightforward.

    But if you wanted to run the explicit test for equality, are you checking for reference or value? With .NET, you're better off using:

    booleanVariable.Equals(true) for value and booleanVariable.ReferenceEquals(booleanVariable2) for reference. There are some issues with ReferenceEquals though.

    Just my peeve

  5. True that, i agree, far more human readable. though, i've learned that shortcut doesn't quit work right in linq statements. i usually still have to use = true/false. i use VB.net, not sure if it's the same in c#.

  6. I agree. I consider if (Adesk::kTrue == booleanVariable) to be just plain wrong given that compiler warnings will unearth the inadvertent = for ==. I am a fan of "treat warnings as errors" settings.

  7. I haven't written my own C++ project for a number of years, now: the last time I did there were issues with using ObjectARX at /W4, but my related memory is fading (I'm running aggressive garbage collection :-). And my own use of this approach almost certainly pre-dates the warning.

    I'm a little curious, though (which is a little cheeky given my pedantic post) what makes reversing the sides of a test to be "just plain wrong"? 🙂

    Kean

  8. In most high level languages the assignment construct is

    <identifier> = <constant> | <expression>

    An if statement is an evaluation as to the results of one of those statements. It just seems so natural to keep the order of

    if (<identifier> = <constant>)

    instead of flipping it around.

  9. Fun article, Kean.

    Way back when computers were made of wood and we used C-shaped rocks to form them into the shape we needed, there were two substantial reasons why boolean comparison was a bad idea:

    1. As you mention, while falsehood was absolute (zero), there were many truths (any non-zero), and the various opinions of truth led to disagreements and bugs. Woe to the developer that was expecting some called subroutine to ascribe to his particular brand of truth. Was isItSafe() going to return TRUE, true, kTrue, etc.? What was the current value of that enum/const/#define in the scope of definition versus use? Get it wrong with an equivalence test and your code has a hard-to-spot bug. Best to just test for non-false, using the naked predicate as you point out.

    2. But perhaps worse, older compilers weren't smart enough to tell whether you were just looking for "some kind of truth"; erring on the side of caution, they aimed to ensure you got the "precise kind of truth" you wanted. And, since there wasn't an easy way to create branches in assembly for specific values other than zero, they'd first *subtract* the value of truth you asked for, then jump if the difference wasn't zero, so
    if (predicate == TRUE) { execute something }
    really became
    test = predicate - TRUE
    jump beyond execution block if test is nonzero.
    Further, because the result of the test was immediately used in the conditional jump, it meant the processor had to wait for the result of the subtraction to be ready, stalling pipelining. You can see this extra subtract (and wait) negatively impacts performance.
    (I've even seen some older compilers subtract zero when encountering an explicit comparison to false. Go figure.)

    Back then, explicit comparisons in boolean statements were both bug-prone and slow. Today, with modern languages and compilers, truth has been reconciled and branching on booleans has gotten smarter. My personal habits were formed in those wilder times and so, wherever the language permits, I side with your preference for straightforward boolean tests.

  10. I see - thanks for clarifying.

    I suspect it comes down to a question of perspective: equality is symmetric, so the order of the sides really doesn't matter (and the fact that assignment isn't symmetric is actually the property we want to take advantage of to help differentiate the test from the operation). But I fully agree that if we can use a compiler to avoid something that renders the code less readable, then we absolutely should.

    It was interesting that once I'd had my"standing on the table" moment, I found it an easy habit and one that saved me on a few occasions (back in the day).

    But I'm indeed grateful I don't have to worry about such things, these days.

    Kean

  11. Thanks, Jeff - very interesting!

    Kean

  12. God article Kean. As I originally started in VB/VBA, it took a little while to get used to omitting the = signs out when I moved to C#. But I read an article a while back that went through very much the same as yours detailing the inconsistencies between compilers and languages for boolean types, and the suggestion was False = 0, True = Anything else, so never check for true, only ever false. That way at least differences can be ignored.

  13. "Mike Tuersley said...

    But if you wanted to run the explicit test for equality, are you checking for reference or value?"

    What do you mean 'reference or value' ????????

    A Boolean is a value type.

    "With .NET, you're better off using:
    booleanVariable.Equals(true) for value and booleanVariable.ReferenceEquals(booleanVariable2) for reference. There are some issues with ReferenceEquals though."

    Ummmmmmm...

    Sorry, that makes absolutely no sense, because a Boolean is a value type, not a reference type. You can't use ReferenceEquals() to tell if two value types refer to the same object, because value types are always copied when they are passed as arguments.

  14. This almost doesn't deserve an answer. You're reading too much into it, Tony. Reference is for references - I was expanding beyond a simple boolean test since this was for pet peeves. Here is a reference example for you:

    object o = null;
    object p = null;
    object q = new Object();

    Console.WriteLine(Object.ReferenceEquals(o, p)); // returns True

    p = q;
    Console.WriteLine(Object.ReferenceEquals(p, q)); // returns True
    Console.WriteLine(Object.ReferenceEquals(o, p)); // returns False

  15. For myself when I moved from one langague to another I found it refreshing that I did not need to include an equals operator. This is programming, and 1's and 0's it is either 1 or 0 no level of grey here so do not aske me twice 🙂

  16. Mike regarding my comments not deserving a reply, well, you really didn't reply to them...

    All you did was show a textbook example of using ReferenceEquals() on a reference type (System.Object).

    You didn't actually reply, because what you wrote conveniently sidesteps the fact I pointed out regarding testing 'references to Value types', and that ReferenceEquals() cannot be used on and serves no purpose for Value Types like System.Boolean.

    If you're having difficulty understanding the basic differences between reference types and value types, I can recommend a good online resource that you might find useful.

    Have a nice day, Mike.

  17. I'm not going to get into a flaming debate on Kean's blog. I realize that you forgot his second sentence:

    "Feel free to post a comment if you agree, disagree or have your own pet coding peeve to share with other readers of this blog."

    I added to the peeve from a value standpoint and then extended it to references since some readers probably have never looked at either method.

    You can twist and try to wiggle out of it but you didn't pay attention to the guidelines Kean established. We all do it occassionally and I forgive you 🙂

    Have a good day, Tony

  18. I'm certainly not a professional programmer and most of the explanations for why I shouldn't do this are over my head. Most of you would consider me inferior only because I like VB. But, by using a 'natural' language for developing, it makes my code easier to read and debug (for ME) if I do include "= True" or "= False". Using "Not" is less intuitive in my humble opinion. Surely even the gearest of gear-heads can understand "If SomeBoolean = True" when they read it even if it's not technically correct. His understanding of the code is the same. Considering the IL is the same, just let it go. 😉

  19. Kean Walmsley Avatar
    Kean Walmsley

    Well, yes - none of this really matters, of course. 🙂

    It's down to a question of perceived elegance rather than technical correctness (both forms are technically correct, just as ((a == true) == true) is techncially correct).

    Kean

Leave a Reply

Your email address will not be published. Required fields are marked *