8

I found the following rule in a coding standards sheet :

Do not rely on implicit conversion to bool in conditions.

if (ptr) // wrong

if (ptr != NULL) // ok

How reasonable/usefull is this rule?

How much overload on the compiled code?

oguz ismail
  • 1
  • 16
  • 47
  • 69
moala
  • 5,094
  • 9
  • 45
  • 66

9 Answers9

15

In the strictest sense, you can rely on implicit conversions to bool. Backwards compatibility with C demands it.

Thus it becomes a question of code readability. Often the purpose of code standards is to enforce a sameness to the code style, whether you agree with the style or not. If you're looking at someone else's standard and wondering if you should incorporate it into your own, go ahead and debate it - but if it's your company's long-standing rule, learn to live with it.

P.S. I just joined an organization that has the same rule. I'm actually fine with it because I've always believed that explicit is better than implicit. The one thing I can't abide though is bool condition; ... if (condition == true), which so redundant that it grates on my eyes.

Any decent compiler should generate the same code whether the check is implicit or explicit, so that shouldn't be a consideration.

Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
  • Yes you can rely on implicit conversions to `bool`, just like you can rely on operator precedences even when the compiler suggests you put in redundant parentheses (for both cases it think there is zero probability the rules will ever change). You can even rely on implicit conversions to bool to come and bite you whenever you forget to dereference a pointer in a position where for some reason such as overloading a `bool` value would also be meaningful. – Marc van Leeuwen Apr 27 '17 at 10:06
6

That rule puts you in a bind if you ever want to use a class that has an implicit conversion to bool, such as std::istream. This code reads a word at a time from a file until EOF is reached:

std::ifstream file("foo.txt");
std::string word;

while (file >> word)
{
    // do stuff
}

The stream extraction operator returns a reference to the file stream, which is implicitly converted to bool to indicate whether the stream is still in a good state. When you reach the end of the file, the test fails. Your coding standard precludes you from using this common construct.

For pointer types, it's not a big deal. The compiler will probably produce about the same code for the implicit conversion to bool and the explicit test against NULL. It's a matter of taste at that point - neither one is "better" in an absolute sense. The coding standard is simply trying to enforce a consistent style.

With that in mind, you should absolutely follow the coding standard when dealing with built-in types (pointers, ints, etc.). If you run into a similar situation to the above with a class having a legitimate conversion to bool, I would raise the issue with your teammates.

Michael Kristofik
  • 34,290
  • 15
  • 75
  • 125
  • 2
    It should be noted that there is some debate as to whether constructs such as the one you've shown are a good idea or not. Hiding non-type conversion functionality behind an overloaded operator falls into the category of 'neat trick', but does it really make things easier to read? Or does it actually make them harder to read until you know about the trick in the library? Similarly with the >> and << operators on the input and output streams - why do bitwise operations do i/o in this special case? It's utterly unreadable until you know the trick. – Michael Kohne Aug 25 '09 at 23:09
  • It's in the online FAQ (http://www.parashift.com/c++-faq-lite/input-output.html#faq-15.4) and it's pretty common code, so a good C++ programmer needs to be able to understand it. I do agree, however, the we can debate the merits of it until the cows come home. :) It served as a convenient counterexample for the OP's coding standard. – Michael Kristofik Aug 25 '09 at 23:16
  • 3
    You can still use this feature while following the rule: `while(static_cast(file>>word))`. At that point the style guide author might want to reword the rule: "Do not rely on the *default* implicit conversion from pointer to bool in conditions", which is probably what was intended in the first place based on the example given. Or he might want to require that the `static_cast` be there, to remind readers that a conversion occurs. You don't need to use implicit conversions, in order to use conversions. – Steve Jessop Aug 26 '09 at 10:04
  • This is an interesting case. Maybe the coding standard should add an exception for where the implicit conversion results in a call to a conversion operator, as in essence a type with such a conversion operator is intended to operate exactly as a bool object. It doesn't make sense to have "b == true" (where b is a boolean) so this logically applies to the conversion operator case. – Richard Corden Aug 26 '09 at 10:25
  • 3
    @onebyone: I look at the original code and I think "this reads words from a file", because I know the standard library (like any C++ programmer should; that construct is idiomatic). I look at your code and I think you're trying to force it to do something it doesn't want to do, and that makes me scared. If I saw your code in real life, I'd probably spend 10 minutes trying to verify that it wasn't a major bug, and once satisfied that it wasn't broken, replace it with Kristo's version. – rmeador Aug 26 '09 at 14:33
  • I'm just saying how to follow the rule, not advocating the code. That's why the style guide should be updated to address it one way or the other. If you haven't read the guide, you won't be dealing with the code either. If you have, then local idioms have priority over general C++ style. The author of this style guide appears to want programmers to pay attention when conversions occur. I might not have that goal myself, but if people find my code snippet confusing, that suggests they don't readily understand what conversion the usual idiom performs. If anything that supports the author's case. – Steve Jessop Sep 02 '09 at 12:27
4

In most cases, it's not horrible, but it can be more readable if you type exactly what you mean.

Matthew Scharley
  • 127,823
  • 52
  • 194
  • 222
  • I can't find a reference immediately, but I don't think what you say is correct. I think the standard defines NULL as being equivalent to zero. Either way, I couldn't name a single system where that isn't the case... – Jon Bright Aug 25 '09 at 22:15
  • NULL is 0 (up to casting) on all remotely standards compliant systems. Some esoteric implementations might compile pointer 0 to something other than 0, but it's still 0 in the code. – Captain Segfault Aug 25 '09 at 22:16
  • I still don't have a link for you, but from p102 of my copy of K&R: "Pointers and integers are not interchangeable. Zero is the sole exception: the constant zero may be assigned to a pointer, and a pointer may be compared with the constant zero. The symbolic constant NULL is often used in place of zero, as a mnemonic to indicate more clearly that this is a special value for a pointer." So NULL certainly *should* be equal to zero on all systems. – Jon Bright Aug 25 '09 at 22:18
  • I stand corrected, the language covers up this implementation detail. That said, not all systems use 0 internally, but most do because it enforces null dereference errors by causing memory errors. – Matthew Scharley Aug 25 '09 at 22:21
  • Well, the standard says "The macro NULL is an implementation-defined C++ null pointer constant". And also, in pointer conversions, "A null pointer constant is an integral constant expression rvalue of integer type that evaluates to zero." – Rüdiger Hanke Aug 25 '09 at 22:25
  • @Jon Bright, I don't think K&R is a reliable reference for the current standards. – strager Aug 25 '09 at 22:26
4

I wanted to add a historical view to this question.

ANSI C (aka C89/C90) was the first formal specification for C. Along with K&R C, you might notice something peculiar—there is no concept of a boolean. Control flow statements operate on expressions, and their flow is defined based on whether the expression evaluates to 0 or not. The lack of a boolean type is one of the biggest oversights of C. It wasn't until C99 that C gained the _Bool type, and defined macros for bool, true, and false in stdbool.h (note they are still integers). Likewise, C++ didn't originally have a boolean type, either, gaining it in C++98 with bool.

This is why there are implicit conversions to booleans. In my opinion, continuing to rely on that is bad design—booleans were added for a reason. true should always equal true, and the implicit conversion of all non-zero values as true is unsatisfactory.

NULL is also just a macro equal to zero, so specifically, for pointers in C++11, you should be using nullptr to determine if a pointer is null.

if(ptr != nullptr)
{
    // Do something with ptr.
}
lordcheeto
  • 1,092
  • 12
  • 16
2

Sometimes I think this rule can be broken, when e.g. dealing with standard libraries which return int instead of bool (for compatibility with C89).

However, this rule generally leads to easier-to-understand code. It's even enforced in languages like C# and it's not complained about too much there, so there are no major downsides to following this rule other than having to get used to it.

strager
  • 88,763
  • 26
  • 134
  • 176
  • I agree with the second part about other languages doing it using 'strong bool' style, but I disagree with the sentiment about breaking the rule when dealing with C-style functions/libraries. Personally I think anything returning an `int` should be compared against 0 to make it clear to the readers of your code what's going on. For example `if(someAwfulCStyleFunction() != 0) { /*error handling code*/ }` clearly implies "this function returns an `int` and a non-zero value represents an error". – Pharap May 08 '19 at 13:35
1

This won't affect the compiled code at all.

As for how useful it is - it'll certainly aid comprehension for people coming from languages such as Java/C#. It'll make it more explicit what you're checking for. It'll throw a warning if you start comparing ints to NULL (and thereby indicate that you're hazy about the type of the variable in question). I personally prefer the first form, but it's not a totally unreasonable requirement.

Jon Bright
  • 13,388
  • 3
  • 31
  • 46
-1

I dislike this rule very much. It is idiomatic in C++ to use the implicit conversion to bool for pointer types (and of course for boolean types). IMO, it is much easier to read

bool conditionMet = false;

while (!conditionMet) // read as "while condition is not met"
{
    /* do something */
}

than it is to read this:

bool conditionMet = false;

while (conditionMet == false) // read as "while conditionMet is false"
{
    /* do something */
}

It's the same for pointers. Also, by introducing the unnecessary comparison, you're introducing yet another opportunity to mistype and end up with an assignment instead of a comparison, which of course will produce undesired results. In cases where you're using ints as bools, as with old C code, I think you should also use the implicit conversion to bool.

rmeador
  • 25,504
  • 18
  • 62
  • 103
  • 2
    I'd argue that for `bool` types it's not coercing anything (despite what the compiler may or may not do). For pointer types it's a little more grey. With anything else, you should be using a comparison operator. – Matthew Scharley Aug 25 '09 at 22:55
  • You're comparing apples to oranges. Your examples use no implicit conversion, merely redundancy. – Pharap May 08 '19 at 13:29
-2

A rule that adds zero benefit is a rule you can profitably delete.

soru
  • 5,464
  • 26
  • 30
  • 4
    But there are benefits, not least of all to readability. Just because you don't like it doesn't mean it doesn't have it's upsides. – Matthew Scharley Aug 25 '09 at 22:18
  • I neither like it not dislike it, just don't think it has a valid reason to exist as a rule. You only get about 40 or 50 rules in a manageable coding standard - don't waste them. – soru Aug 25 '09 at 22:25
  • I'm not clear that it doesn't add benefit. For pointers it's marginal, but I've dealt with a lot of code where folks do this all the time with ints and it's a damned nuisance when it has to be changed. – Michael Kohne Aug 25 '09 at 23:11
  • It also adds a risk... if you meant to type "if (ptr != NULL)" and you accidentally drop the exclamation point and type "if (ptr = NULL)" instead, you've added a rather nasty bug into your program. If you type "if (ptr)", you don't run that risk. (OTOH, you should get a compiler warning in any case) – Jeremy Friesner Aug 25 '09 at 23:48
  • 2
    However one could similarly mean to write "if (!ptr)" and accidentally miss the keystroke, resulting in "if (ptr)". A different bug, but just as nasty, and which the compiler cannot warn about. – TheUndeadFish Aug 26 '09 at 04:06
  • @Jeremey: Another coding rule: "Always place the rvalue on the left of the equality operators so that it will fail to compile if you make the mistake -> "if (NULL = ptr)" ;) – Richard Corden Aug 26 '09 at 09:26
-5

That's an impressively stupid rule.

if (ptr != NULL) // ok

then why not

 if ((ptr != NULL)==true) 
Martin Beckett
  • 94,801
  • 28
  • 188
  • 263