views:

578

answers:

8

I was looking at some example C++ code for a hardware interface I'm working with and noticed a lot of statements along the following lines:

if ( NULL == pMsg ) return rv;

I'm sure I've heard people say that putting the constant first is a good idea, but why is that? Is it just so that if you have a large statement you can quickly see what you're comparing against or is there more to it?

+42  A: 

So that you don't mix comparison (==) with assignment (=).

As you know, you can't assign to a constant. If you try, the compliler will give you an error.

Basically, it's one of defensive programming techniques. To protect yourself from yourself.

Developer Art
Brilliant - thanks a lot :-)
Jon Cage
+5  A: 

When the constant is first, the compiler will warn you if you accidentally write = rather than == since it's illegal to assign a value to a constant.

liwp
+19  A: 

To stop you from writing:

 if ( pMsg = NULL ) return rv;

by mistake. A good compiler will warn you about this however, so most people don't use the "constant first" way, as they find it difficult to read.

anon
+1 after your ninja edit.
280Z28
+1 for mentioning that modern compilers warn about this anyway. Another reason to not do it in C++ is to avoid pitfalls with poorly written operator overloads. (`_bstr_t`, oh, how I hate you.)
jamesdlin
+1 for mentioning the readability/maintenance issues.
Ben
+7  A: 

It stops the single = assignment bug.

Eg,

if ( NULL = pMsg ) return rv;

won't compile, where as

if ( pMsg =  NULL) return rv;

will compile and give you headaches

Dan McGrath
+2  A: 

They said, "to prevent mixing of assignment and comparison".

In reality I think it is nonsense: if you are so disciplined that you don't forget to put constant at the left side, you definitely won't mix up '=' with '==', would you? ;)

Alexander Poluektov
No, but, you have more of a chance averting the mistake with something that takes multiple keystrokes than one that could be caused by not typing quite hard enough to get the second =. Hence, you know, typo.
Dan McGrath
I'm just curious how often did you do such typo? Bet you didn't.
Alexander Poluektov
I'd like to think I'm fairly disciplined, but whatever your coding style, everyone makes the occasional typo and this simple habit avoids mistakes like that making it through to execution. A bug caught at compile time is worth 10 at execution time :-)
Jon Cage
+1, "bug caught at compile time is worth 10 at execution time" - Quote of the day!
KMan
@Jon Cage: But most compilers warn about possibly unintentional assignment anyway, and the constant-first-approach can introduce different run-time bugs in C++ code.
jamesdlin
@Jon Cage, @KMan, @Dan McG You are just fight windmills now. Still, how often did you do such typo?
Alexander Poluektov
In this case (also when dealing with bool's), IMO the surest way is not to compare against NULL (true/false) explicitly. `if (!pMsg)...`
visitor
I made this typo a few weeks back actually and the Microsoft compiler I'm using _didn't_ warn me for some reason. What's a fight windmill?
Jon Cage
+1, because i strongly believe that being cautious while coding is much more important than following so-called defensive rules (because the list is never long enough)
Benoît
@Jon Cage: sorry, "fighting windmills" from Don Quixote: by this I meant that problem is far-fetched a bit IMVHO.
Alexander Poluektov
@Benoit: There's nothing wrong with benig cautious _and_ taking precautions though right?
Jon Cage
@Jon Cage : no there isn't. But my everyday experience is that people often over-trust precautions and eventually consider cautiousness unnecessary.
Benoît
Well more fool them then. I agree that you should never stop being contientious when you're writing code, but if you can reduce the possibility of accidental mistakes it seems silly not to! :-)
Jon Cage
The problem with this (CONST == var) order is that is mixes up the Subject-predicate order which is natural for most western languages. The subject is the main actor in a sentence, and the main actor in the equality is the variable, not the constant. This is why this seems unnatural and is hard to read, like a sentence in the passive voice. So there is a good reason to avoid the (CONST == var) construction.
Tim Schaeffer
Yes, like Yoda speak it reads. Also, what if two mutable values you were to compare, would the more awkward order you try to pick just to be consistent with the style ;)
UncleBens
A: 

Compilers outputting warnings is good, but some of us in the real world can't afford to treat warnings as errors. Reversing the order of variable and constant means this simple slip always shows up as an error and prevents compilation. You get used to this pattern very quickly, and the bug it protects against is a subtle one, which is often difficult to find once introduced.

SteveV
+4  A: 

To clarify what I wrote in some of the comments, here is a reason not to do this in C++ code.

Someone writes, say, a string class and decides to add a cast operator to const char*:

class BadString
{
public:
   BadString(const char* s) : mStr(s) { }

   operator const char*() const { return mStr.c_str(); }

   bool operator==(const BadString& s) { return mStr == s.mStr; }

   // Other stuff...

private:
   std::string mStr;
};

Now someone blindly applies the constant == variable "defensive" programming pattern:

BadString s("foo");

if ("foo" == s) // Oops.  This compares pointers and is never true.
{
   // ...
}

This is, IMO, a more insidious problem than accidental assignment because you can't tell from the call site that anything is obviously wrong.

Of course, the real lessons are:

  1. Don't write your own string classes.
  2. Avoid implicit cast operators, especially when doing (1).

But sometimes you're dealing with third-party APIs you can't control. For example, the _bstr_t string class common in Windows COM programming suffers from this flaw.

jamesdlin
I've seen a lot of places that ban operator overloading in general. Yay C++.
jeffamaphone
Wouldn't s=="foo" have the same problem though?
Jon Cage
@Jon Cage: No. Unintuitively, while `"foo" == s` doesn't trigger a desired ambiguity error, `s == "foo"` does. (The author might then implement `bool MyString::operator==(const char*) const` which will resolve the `s == "foo"` ambiguity but still do nothing to fix `"foo" == s`.)
jamesdlin
@James: Am I right in thinking the `"foo" == s` case isn't handled there because it's handled by whatever type `"foo"` equates to (a const char*?); hence the pointer comparison?
Jon Cage
@Jon Cage: I don't understand what you mean by "handled by whatever type..." when it's a primitive type. In this case, the compiler silently coerces the RHS from a `BadString` to a `const char*` via its cast operator and then compares pointers.
jamesdlin
@James: Bad terminology on my part; what you've just said is what I was getting at. Thanks very much for the explanation :-)
Jon Cage
A: 

I forget the article, but the quote went something like: "Evidently its easier remembering to put the constant first, than it is remembering to use ==" ;))

Joe