6 ms·
> There is an implicit "x != 0" in: if (x), while (x), ... etc. > An explicit "x != 0" in these contexts serves no semantic purpose. > And "x == 0" in these
by nayuki 7y ago
> There is an implicit "x != 0" in: if (x), while (x), ... etc.
> An explicit "x != 0" in these contexts serves no semantic purpose.
> And "x == 0" in these contexts might be better written as "!x".
I disagree with this advice because the idea is not portable across languages.
For example, if we let the variable x hold the integer value 0, then:
Java 'if (x)' is a compile-time type error.
Python 'if x:' is falsy, similar to C.
Ruby 'if x' is truthy!
- chupa-chups 7y agoWhile this is technically correct, idiomatic javascript differs from idiomatic ruby, which (that is the point) differs from idiomatic C. So either no idioms are correct, or it is correct to apply the idioms pertaining to the language of choice.
- TickleSteve 7y agoCompletely agree... but the most serious issue is that it does not read well. Consider how you would read it: "if grass is green ..." is effectively shortened to "if grass ...". This makes no sense. I always use explicit conditions and consider "if(x)" and antipattern and have done since I was learning C back in the mid eighties.
- smcl 7y agoUnfortunately your example doesn't illustrate the point very well: if (grass_is_green) { ... } vs if (grass_is_green != 0) { ... } or if (grass_is_green == 1) { ... } The one with the implit comparison to zero is more readable
- zormino 7y agoCertain industries also have guidelines that chime in on this issue. Where I work, we have to create defines for TRUE and FALSE, and everything needs to be compared to them. Essentially making things look like if (bool_name == TRUE) There is no ambiguity, and it forces you to handle exactly equal to 1 and not equal to zero separately. if (bool_name == TRUE) and if (bit_field_value > 0) are logically different even if they can be simplified to the same thing.
- enriquto 7y agooh my god, this is horrific. I suppose you are just trolling. There's no way this can be an accepted practice anywhere.
- userbinator 7y agoAs someone who has actually worked with a codebase with plenty of such expressions, I suspect it was really an "accepted practice" at some point in time, stemming from a mindless interpretation of the "be explicit" guideline taken too far. The worst part is that sometimes these redundancies grow and combine to create even more confounding expressions, frequently resulting in monsters resembling this: if ( ((((!(var)!= FALSE)) != TRUE)) ) { return FALSE; } else { return TRUE; }
- marcoperaza 7y agoThat is bad practice IMO because it makes it easy to accidentally introduce bugs and produces code that a reader will misinterpret, making it harder to find bugs. The better approach is to always compare against FALSE, because that avoids the ambiguity of == TRUE only catching a single truthy value out of the millions of possible truthy values, contrary to the well-known semantics of C. If you really need to distinguish between 1 and other truthy values, then just compare against 1 explicitly. Don't muddle the concept of truthiness.
- zormino 7y agoAll times where a Boolean value would be assigned, it must be explicitly checked and then set to either TRUE or FALSE. The reason is for writing embedded code that doesn't depend on a specific compiler or architecture, which is important when code that was written in the 80s is still getting used everyday in new safety critical systems, where any kind of standard libraries are forbidden. I agree it's not the best but it's definitely not uncommon.
- kazinator 7y agoIn C, comparing boolean-like variables to true and false constants is bad practice. The comp.lang.c FAQ touches upon this: http://c-faq.com/bool/bool2.html http://c-faq.com/bool/bool2.html
- kazinator 7y agoThe one with the implicit comparison is more readable because it's closest to simulating the test of a Boolean variable. The other two leave the reader with the lingering suspicion that the variable takes on two or more values. The latter more so than the former.
- raverbashing 7y agoYeah... Ruby is in the wrong there. Not even js does that Insisting if takes a bool like java does is perfectly acceptable. But just taking a 0 value and making it "true" makes sense only in Bash?
- lmkg 7y agoIt depends on what the set of falsey values is for that language. E.g. in Common Lisp, the only falsey value is NIL (the empty list). This is easy to understand, easy to remember, and straightforward in practice because idiomatic Lisp does a lot of list operations. It wouldn't make sense for 0 to be truthy, because that's a legit value, and NIL represents the absence of a value. I don't know what values are falsey in Ruby, so I can't comment on it.
- samatman 7y agoLua does this as well, and I quite prefer it. If I return a number or nil, I want to check `if ret`, not `if type(ret) == "number"`. The latter suggests that it might be some other type‡, the former that it might be missing entirely. A language which provides a proper Boolean has no need for the association between zero and falseness, it is a conflation of levels which can lead to subtle bugs. ‡ yes, nil is also a type. I mean some other type of type.
- dnautics 7y agoerlang and erlang VM languages come with 0 being truthy, and the only falsey values are false and nil. I had a junior python programmer disagree with that and within 3 weeks of onboarding him we found a place where it made sense for 0 to be a truthy value. I believe it was a place where we had an options list. One of the options was a value that is settable to zero. In elixir: timeout = options[:timeout] || :infinity if zero is falsy, you can be royally screwed with that code, if timeout should be settable to zero (definitely a thing).
- int_19h 7y agoIt makes a lot more sense when you consider that all values in Ruby would be pointers in C. And if x is a pointer to int, if(x) is still checking whether the pointer itself is null, not whether the int it points to is 0.
- turgidson 7y agoDo you stick to features portable across all languages for all your code?
- saagarjha 7y agoMaybe they only write polyglots :)
- LadyCailin 7y agoYes. This is why I exclusively write polyglot source files, so you can choose to compile my code in either c++ or php or bash or whitespace. Jokes aside, polyglot source files are pretty cool, and generally things like abuse of the c++ preprocessor are really neat to see, if completely unwise to do in production.
- marcoperaza 7y agoThe advice in the article is too broad because there are times when the comparison is not meant in the truthy/falsy sense. For example, strcmp and friends return 0 if the strings are equal, less than 0 if str1 is lexically less than str2, and more than 0 if str1 is lexically greater than str2. So if(!strcmp(str1,str2)) is a valid way to check for equality, but I think the negation makes it confusing; it is tempting to intuitively read it as checking if the strings are not equal. if(strcmp(str1,str2) == 0) is the better choice.
- a1369209993 7y agoCalling it (eg) strdiff instead would help here, if(!strdiff(str1,str2)) matches the intuitive interpretation.
- saagarjha 7y agoIt's a three way comparison, not an equality one. If you treat it like that then the return value makes more sense.
- a1369209993 7y agoSure - thats why it shouldn't be str_ne or similar. strDIFF (or rather, strcmp) returns the direction in which strings DIFFer - less than (negative), greater than (positive), or equal (zero).
- LessDmesg 7y agoIt's not meant to be portable. It's just that C is a low-level, weakly-typed language where everything is bytes and bits, and every pointer may be null at any moment. Disregarding type-safety is OK for C, so it's handy to conflate 0 and false (after all, bools are isomorphic to positive numbers modulus 2). It's these other languages who are in the wrong because any high- or medium-level language must have proper Option and Bool types without null or false infecting every type out there.