The Design of Software (CLOSED)

A public forum for discussing the design of software, from the user interface to the code architecture. Now closed.

The "Design of Software" discussion group has been merged with the main Joel on Software discussion group.

The archives will remain online indefinitely.

"not" or "= False"

A guy at work rarely uses "not" in if statements. For example, I would write

if not AceFunction(AParameter) then

whereas he would write

if AceFunction(AParameter) = False then

I find his code difficult to read because of this. Is there any reason other than this why he should use not instead of = False?

(The code's in Delphi.)
cja Send private email
Sunday, August 21, 2005
 
 
We don't just use Delphi, though, so other languages matter too (VB .Net, particularly).
cja Send private email
Sunday, August 21, 2005
 
 
Because

  if var == false

Could be typo'd as

  if var = false


Even if you're working in a language like VB with a single '=' for assignment and equality, very few people work in just one language, so learning consistency is important.
Nick Hebb
Sunday, August 21, 2005
 
 
Maybe suggest your coworker this is even easier:
"if AceFunction(AParameter) XOR True then"

That way you can express any guard by comparing it with True.

Or you can always go for the NAND True way. But it's an extra character, so it's not quite as convenient.
General Protection Fault
Sunday, August 21, 2005
 
 
I worked for a company whose senior C++ person insisted that if you don't compare to a logical value the compiler gets the wrong answers.

So all the code had to say "if ((foo==bar)==true) ... "

VERY screwed up company that. Amusingly it's one of the ones on my CV that people go "wow.. you worked at ---? they're a big technology leader..." etc.

Wierd how that happens isn't it?
Katie Lucas
Sunday, August 21, 2005
 
 
I suspect I'm in a minority but I find the "= False" much easier to read. Even if I’m checking if a function has returned a true value I will explicitly statue it..

if FuncCall(x,y) = True then

I find it easier to read when I go back to it at a later date.
Ian H. Send private email
Sunday, August 21, 2005
 
 
Personally, I always prefer to write out " == false " or " == true " for the same reason you dislike it -- consistancy.

In many languages these are all valid:
if (booVariable)
if (!booVariable)
if (not booVariable)

and this also leads to things like this
if (!booVariable == false)

and that just sucks.

so my solution is to just use ==true or ==false and my code only has 2 possibilities:
if (booVariable == true)
if (booVariable == false)

and THAT'S consistant.

Shane
Shane Harter
Sunday, August 21, 2005
 
 
It seems to me the real problem is that the name of the function ("AceFunction") doesn't indicate that it returns a boolean, nor does it indicate what you're testing.  There are functions like this where I work, and it drives me up the wall.  Stuff like:

If Not SendFile Then...

The true/false indicates success, and I can see where return true or false is better in some ways than throwing an exception, but the fact remains that it's an unclear idiom.  What are we evaluating as true or false: "It succeeded" or "It had an error of some sort"?
Kyralessa Send private email
Sunday, August 21, 2005
 
 
I avoid using NOT as much as possible, if you are in the habit of using it then you are likely to start ending up with double negatives.

much clearer and simpler (and more consistent as the above poster states) to just compare with true or false IMO.
Jesus H Christ
Sunday, August 21, 2005
 
 
I prefer writing !(condition) instead of condition==false, mainly because it's shorter, but that's a matter of personal taste.

Similarly, my code would say,
  b = (foo == bar);
when I've had coworkers who prefer
  b = false;
  if (foo == bar) {
    b = true;
  }
Julian
Sunday, August 21, 2005
 
 
There are various reasons why I don't like to use a comparison to a logical value, e.g., if ( a == false ) do something;

It's easier to get away with in C++ since it has the bool type, but I learned C first.  In C zero it treated as false, not zero is true for the conditional.

Suppose you had, in C:
#define FALSE 0
#define TRUE  1
if ( func( arg ) == TRUE ) do something;

How would you know what func() was going to return for a true value?  Unless you are totally consistent in use of the defines you could get unexpected results.

Besides this, it's just ugly code.
argon
Monday, August 22, 2005
 
 
"I prefer writing !(condition) instead of condition==false, mainly because it's shorter, but that's a matter of personal taste. "

right, I prefer ==false over not, but I would also prefer  b = (foo == bar); over the alternative you offer.

to me its not about shorter, or longer, its about possibility for misunderstanding.

to me:
if NOT object.isGood()  (or if !object.,isGood())

is marginally less good than:
if object.isGood()==false

just because it takes me a breif saecond to work out the nots and goods and ensure that they make sense.
also Ive seen people in the habit of using ! or not write code like:
if(!object.isBad())
which to my mind is madness, double negatives are the work of the devil and I should never, ever have to think for even a second to be able to understand such a essentially simply if statement.

...also you just know that some asshat is going to come along and tweak it like so:

if(!object.isBad()==otherObject.notGood())


better to have a habit that says:  make it explicit.

...and another that says "anyone writing a double negative into an if statement deserves to have a sheepdog jammed up their ass"


dont aim for shorter code, aim for more readable code..often that means shorter, often it means longer.
Jesus H Christ
Monday, August 22, 2005
 
 
Explicit testing may be okay in languages with a boolean type and strict type safety. NEVER ever use it in C. And make sure it isn't a sign of a nonunderstanding of bools.

For direct comparisions, no one would write

if ((a == 2) == TRUE)

Or would you?

As a function return value for a function with a less-than-optimal name choice, it is often better to use explicit return values instead of an anonymous boolean:

if ( SendFile() == SF_SUCCESS )
if ( SendFile() == SF_FAILURE )

instead of

if ( SendFile() )
if ( SendFile() == TRUE )

Additionally, this allows for later extensions without breaking the existing code:

if ( SendFile() == SF_MAYBE )
Secure
Monday, August 22, 2005
 
 
At my workplace, we set up the following recommendation (in C++):

Use ! (or nothing) only for boolean expressions, otherwise, use binary comparison operators.

The issue here is that sometimes people use things like ! to mean "not positive" or "non-null".  Ergo, for a pointer, you should use

if ( ptr != NULL )

rather than

if ( ptr )

This recommendation has a nice effect when consistently applied.  Whenever you see a ! (or not, whatever) you know that the function returns a bool or value really should be a bool.  With pointers, when actually being compared with NULL, you get a nice way of quickly finding memory-related code within a function.  While definitely not critical, it just is has one of those nice effects of speeding up code reading.  Consistency is important, however.
Tristan Juricek Send private email
Monday, August 22, 2005
 
 
I was always taught to use  == false when doing comparisons, simply because using NOT could lead to a double negative (as stated earlier) and those can be difficult to read.

I have seen a lot of:  if not x == false

Why not just use if x == true?
Eric D. Burdo Send private email
Monday, August 22, 2005
 
 
Sometimes, I'd phrase this as a matter of choice/preference. But at my current office, there are a number of spaghetti tests, so I end up refactoring them with parentheses everywhere: it cuts down on unexpected side effects from operator precedence issues.

If you've got mostly simple conditionals, then
if not bTest then
is basically the same as
if false == bTest then

If you've got tests so spaghettified that they span several rows of code, then being totally explicit, with enough parens that it almost looks like lisp, is one step in the correct direction.
Peter
Monday, August 22, 2005
 
 
Most of the problems mentioned here can be avoided by using a temporary boolean with an explicit naming and simplifying the if-clause to this single boolean:

Instead of
  if not AceFunction(AParameter) then
or
  if AceFunction(AParameter) = False then

simply use something like this:

  HasFailed = not AceFunction(AParameter)
  if HasFailed then

This gives a plain clear hint what is tested while separating the specific function logic from the program flow logic, instead of mixing both together.
Secure
Monday, August 22, 2005
 
 
> I have seen a lot of:  if not x == false
> Why not just use if x == true?

The above two expressions are the same only if x is boolean; they aren't the same otherwsie, for example when x equals 2:

* "x == false" is false and so "not (x == false)" is *true*

* "x == true" is *false* (assuming that "2" and "true" are not the same value)
Christopher Wells Send private email
Monday, August 22, 2005
 
 
In languages that have many different values equating to logical true or false (like Perl and C), using "not" for all relational checks might not be appropriate.  The (!ptr) example in C is a good one, because logical false might not have the same value as NULL on different architectures.  (ptr != NULL) yields the expected behavior on any platform.

In Perl it's even worse.  If (!$scalar) tests true, it might be a null reference, an integer zero, an empty string, or an undefined variable.  Sometimes you need to know which it is.

I like what one poster said about only using not for true boolean tests:

(!strcmp(a,b)) is inferior to (strcmp(a,b)==0) by that idea, because strcmp has three possible answers instead of a simple "equal/not equal"; not to mention the fact that logical false means the strings are equal.
Matt Brown
Monday, August 22, 2005
 
 
Matt,

"The (!ptr) example in C is a good one, because logical false might not have the same value as NULL on different architectures.  (ptr != NULL) yields the expected behavior on any platform."

(!ptr) is perfectly valid on all standard-conforming implementations:

http://www.eskimo.com/~scs/C-faq/q5.3.html

And BTW, (!ptr) checks for (ptr == NULL).

"(!strcmp(a,b)) is inferior to (strcmp(a,b)==0) by that idea, because strcmp has three possible answers instead of a simple "equal/not equal"; not to mention the fact that logical false means the strings are equal."

One of the cases where macros will help:

#define StrEqu(a,b) ( strcmp((a),(b)) == 0 )

Don't use strequ, it collides with the standard library namespace.

Maybe even better, as already mentioned above, encode your intent into a temporary variable name:

AreEqual = (strcmp(a,b) == 0);
if (AreEqual) ...
Secure
Monday, August 22, 2005
 
 
I prefer explicit checks, personally.

And for safety, in C, the defines are:

#define FALSE 0
#define TRUE !FALSE

This matches the default C behavior of an 'int' which is zero meaning false, while an 'int' which is not zero means true.

Then you can do

if (MyCall(Parm) == TRUE)
{
  // Then do this stuff -- MyCall must return 0 on false
  // Anything else for TRUE.
}
AllanL5
Monday, August 22, 2005
 
 
Allan,

if you are not trolling, someone should tell you that

#define FALSE 0
#define TRUE !FALSE
if (MyCall(Parm) == TRUE)

expands to

if (MyCall(Parm) == !0)

which results in

if (MyCall(Parm) == 1)

The resulting 1 is somewhat different from "Anything else [than 0]". This whole behaviour is guaranteed by the ANSI Standard.

But I don't think you are not trolling. Does the previous sentence evaluate to FALSE or TRUE? ;)
Secure
Monday, August 22, 2005
 
 
"(!ptr) is perfectly valid on all standard-conforming implementations"

Huh, I didn't know that.

Does the internal behavior of (!ptr) change if you explicitly define NULL to be something else, or is the null pointer constant internal to the compiler as well?
Matt Brown
Monday, August 22, 2005
 
 
+1 Secure

That is one reason I don't like to do a compare to TRUE or FALSE.  That scheme only works if you can be sure that MyCall will use the same defines for return values.  Great potential for obscure bugs.


The other reason is that making the comparison to TRUE or FALSE is like trying to overlay a another definition for logical values on top of the one used by C.  That is, the function MyCall is returning a logic value represented by the symbols TRUE and FALSE, then being converted to the C logic values by the comparison (e.g. MyCall(parm) == TRUE) for the if() statement to test.

Why not just have the function return a C logic value and test it directly, e.g., if ( MyCall(parm) ) { do stuff; }?
argon
Monday, August 22, 2005
 
 
NULL is simply a preprocessor macro; it won't affect any statement in which the term NULL is not involved - preprocessing happens before the compilation, doing a simple text substitution for macros. The result is passed to the compiler - that's why Allan's !FALSE won't work, since the compiler does not know anything about macros.

There is the NULL macro, often simply of the form

#define NULL 0

and there are pointers holding a representation of the value NULL, giving a null pointer. Note that "value" and "representation" are abstract conceptions deeply embedded in the C language.

If you are interested to learn more about the topic and to deepen your understanding of C, I strongly recommend a complete read of the comp.lang.c FAQ, esp. the chapter about Null Pointers for your questions. It is more than worth the time to read it, and a must-read for serious C programmers, anyway:

http://www.eskimo.com/~scs/C-faq/top.html

If I ever need to hire a C programmer, one of my interview questions would be: What is the comp.lang.c FAQ?
Secure
Monday, August 22, 2005
 
 
The more useless the subject, the more opinions you'll get.
hoser Send private email
Monday, August 22, 2005
 
 
i ussualy named my function with prefix "Is" if it returns boolean type. For example "IsBalance()", "IsValid()". It would be easier to read the code, even you put NOT when you call the function... :) (i work on VB)
Drury Yudistira Lumenta Send private email
Monday, August 22, 2005
 
 
Use intermediate booleans and test for a simple truth condition, since testing for falsity or complex boolean conditions is something that many find difficult to understand.

Eg

bool isFileAtEof = file.eof();
bool haveFoundItem = file.item().matches(target);
bool notFoundOrEnd = ! (isFileAtEof || haveFoundItem);
if( notFoundOrEnd ) { ... }

And for those who advocate "if( isSomething == true )", instead of if( isSomething ), I suggest you contemplate the following series:

1) if(isSomething)
2) if(isSomething == true)
3) if((isSomething == true) == true)
4) if(((isSomething == true) == true) == true)

If you don't stop at the first condition, why stop at any other point?

Personally, I'm happy reading complex boolean conditions (studied logic at college), but for clarity, far best to combine into a single value that's given a legible name and tested as a simple if(condition).

That's my 2 conditional cents anyway
Matthew Morris
Tuesday, August 23, 2005
 
 
> (!ptr) is perfectly valid on all standard-conforming implementations

Relying on all compilers to be completely standards conformant is foolish.

Tuesday, August 23, 2005
 
 
Not checking whether something works on your platform is foolish, I agree: irrespective of whether it's supposed to work or not.

But not using idiomatic language constructions is equally foolish.

And "if( ! ptr )" is a pretty common construction that works on GCC, Forte and MSVC. I'd view it as a perfectly sensible way of checking for a pointer being non-null.
Matthew Morris
Tuesday, August 23, 2005
 
 
Anonymous:

"Relying on all compilers to be completely standards conformant is foolish."

A compiler which is not standards conformant is broken. If one idiom does not work as expected, what makes you sure that any other idiom works as expected? What makes you sure that a=1+2 will result in 3? How far can you trust a broken compiler, and why? How do know which idioms are safe to be used?

Matthew:

'And "if( ! ptr )" is a pretty common construction that works on GCC, Forte and MSVC. I'd view it as a perfectly sensible way of checking for a pointer being non-null.'

Again: if(!ptr) checks for a pointer being NULL, if(ptr) checks for a pointer being non-NULL. Don't associate the '!' with the 'non'.
Secure
Tuesday, August 23, 2005
 
 
BTW, when you have problems with this, don't use the compressed idioms with implicit checkings, always check explicit (except when the values are already booleans, of course):

if (ptr != NULL)  idiom: if (ptr)
if (ptr == NULL)  idiom: if (!ptr)
Secure
Tuesday, August 23, 2005
 
 
The way I always remember it is

  if (ptr) { I have a valid pointer }
  if (!ptr) { I don't have a valid pointer }

See?  Perfectly logical.  And I defy ANYONE to find a working C compiler that does not implement this ancient and fundamental part of the standard.
Iago
Tuesday, August 23, 2005
 
 
I'd quibble with the word "valid" in the last post. A pointer to freed memory is not valid, though it's also not null.
Julian
Tuesday, August 23, 2005
 
 
There is only ONE way to do this sensibly:

Delphi: if (not blabla)

C++: if !blabla
Frank de Groot Send private email
Tuesday, August 23, 2005
 
 
Julian,

it is even worse with the "validity" of pointers. If I remember correctly, there were long discussions in comp.lang.c about this, with the conclusion that this results in undefined behaviour, because the pointer becomes indeterminant with the free operation:

  p = malloc();
  ...
  free(p);
  ...
  if (p)  /* Undefined behaviour */
    ...

The simple solution is: Always initialize any pointer with NULL, and set it to NULL when the object it points to is no longer valid:

  type *p = NULL;
  p = malloc();
  ...
  free(p);
  p = NULL;
  ...
  if (p)  /* Okay, it is NULL */

As for the mnemonic, the correct wording would be:

if (p)  (I have a non-NULL pointer)
if (!p) (I don't have a non-NULL pointer)

I think "valid" is a good-enough wording for non-NULL to avoid the double-negative. If it is invalid, the whole program becomes invalid out of undefined behaviour, anyway, thus it doesn't really matter.
Secure
Tuesday, August 23, 2005
 
 
I believe that this "== false" thing is from people who learned to program with languages which don't have true booleans.
  Me, I treat booleans as logic values and always use "if ( value )" or use "if ( not value )" because that's how you do logic.
  Would you write as question in English as
  "Is Man Truly Free == TRUE ?"
captain damage
Tuesday, August 23, 2005
 
 
In languages like C where false is one concrete value and true are all ther rest, I guess the best thing is to have defined ONLY the false value, never the TRUE one. For the true ones you have to use a macro or just ask " != FALSE".

myBoolFunc(param) is TRUE ?

if (myBoolFunc(param))          // A1 implicit, shortest
if (myBoolFunc(param) != 0)    // B1 explicit
if (0 != myBoolFunc(param))    // B1'
if (myBoolFunc(param) != FALSE) // C1 (define) verbose
if (FALSE != myBoolFunc(param)) // C1'
if (ISTRUE(myBoolFunc(param))  // D1 (macro) explicit
if (!ISFALSE(myBoolFunc(param)) // E1 !(macro) WTF !!

myBoolFunc(param) is FALSE ?

if (!myBoolFunc(param))        // A0 implicit, shortest
if (myBoolFunc(param) == 0)    // B0 explicit
if (0 == myBoolFunc(param))    // B0'
if (myBoolFunc(param) == FALSE) // C0 (define) verbose
if (FALSE == myBoolFunc(param)) // C0'
if (ISFALSE(myBoolFunc(param))  // D0 (macro) verbose
if (!ISTRUE(myBoolFunc(param))  // E0 !(macro) WTF !!


I'd only get angry with E0,E1 forms, all the other forms are quite clear to read. Just let me add that if in your project you have got the FALSE, [ ISFALSE(),ISTRUE() ] things and it's an standard/suggestion to use them, then C and D would be the suggested forms.

Anyway, it's not so important thing.

And now, just for make this post even longer, about the original question:

> whereas he would write
>  if AceFunction(AParameter) = False then
> I find his code difficult to read because of this.

Are you really serious? "difficult to read" ?

If this is an example of supposed 'poor style/bad code' at your work, all of you are very lucky over there !! What about structure?
Ross Sampere Send private email
Tuesday, August 23, 2005
 
 
Depending on the quality of your compiler....

A == FALSE  (or pref FALSE == A)
produces assembly that needs to load both A and FALSE and compare them and then jmp based on the result

! A
produces assembly that does a jmpne

if you insist on putting in uneccessary equivelance against already boolean equivelant data then you are likely to be slowing the program.

that being said, when you have a non boolean value, it is better form for readability to explicitly compare against a constant - strncmp() in C is classic for confusing people
if( ! strncmp( "A", "A" ) )
  // matches
else
  // doesn't match

Vs

if( 0 == strncmp( "A", "A" ) )
  // no difference


People like to use the same rules everywhere they can, which means if you have some cases where you have to compare 2 values, they try and make all if tests compare 2 values, which is just not necessary.

Style...

you should always put constants on the left to avoid typos and compiler confusion.  just because it's afunction doesn't mean it will allways be const return.

if( READABLE == fileType() )

msvc6 has troubles with
const list<int> foo;
list<int>::const_iterator bar(foo.begin());
if( foo.end() == bar )
reports error that a const can't be used on the LHS - even though it's being used in equivelance.
if( bar == foo.end() )
is acceptable

Tuesday, August 23, 2005
 
 
Ross,

'I guess the best thing is to have defined ONLY the false value, never the TRUE one. For the true ones you have to use a macro or just ask " != FALSE".'

So if you want to assign TRUE to a variable, you need:

  boolvar = !FALSE;

or what? Hm... I'm not impressed. ;)
Secure
Wednesday, August 24, 2005
 
 
> A compiler which is not standards conformant is broken.

Agreed. And there are hundreds (well, several) around. Get used to it.

Wednesday, August 24, 2005
 
 
I think both of them is OK, but the consistency of the code is prefered.
Daniel Send private email
Wednesday, August 24, 2005
 
 
Mr. Blank --sorry if it should be Madam--, in general I agree, but showing C++ + templates + and objets code for having a case where constants on the left are a problem, I find it's a bit overkill!!

About: "if you insist on putting in uneccessary equivelance against already boolean equivelant data then you are likely to be slowing the program.", it's good to know what can happen at the lowest level, but you have to be in a very very special part of the application, or in a very critical and deep bucle, or something like that to need so much caring about every single machine code instruction you can save.

Good point on strncmp(...), it's not a boolean function, it's 3-lean, so don't fool people with the not operator as if it was bo... wait!, using the ! we can go some cpu cycles faster! (joking!)

Secure, I was thinking on comparisons, not on assignments... Well, you got me, here... Let me say I don't hate 1's and 0's on C, so I'd use them as bool values on assignments, and the 0 and ! on comparisons... but let's follow the game, if using 1's and 0's was banned when working with booleans in C... I'll do:

/* Only for assignments : */
#define      FALSE            0
#define    A_TRUE_VALUE        1

/* Verbs : */
#define    ISFALSE(x)  (0 == (x))
#define      ISTRUE(x)  (0 != (x))

boolvar = !FALSE;
boolvar = A_TRUE_VALUE;

if (otherboolvar == A_TRUE_VALUE) <-- error (trying to be verbose)!!

LOL
Ross Sampere Send private email
Wednesday, August 24, 2005
 
 

This topic is archived. No further replies will be accepted.

Other recent topics Other recent topics
 
Powered by FogBugz