1. Computing

D'oh! Those Negative Boolean AND Bitwise Expressions :(

By October 21, 2011

Follow me on:

in D'Oh Moments :: Again, never mind years of programming!

A "D'oh" moment for me is when I do an obvious coding error but I am not able to see it even in the debugger.

Consider the following section of code:

var
  sl : TStringList;
begin
  sl := TStringList.Create;
  try

    if (NOT sl.Count > 0) then ShowMessage('String list is empty');

  finally
    FreeAndNil(sl);
  end;
end;
Would you expect to see the message "String list is empty"? I would. We have only created the string list and just after creating, it should be empty (i.e. the Count property should not be greater than zero).

However the message does not get displayed :(

Of course, in my real-world code the entire boolean expression was much more complicated containing several AND'd and OR'd parts.

Now, why the "(NOT sl.Count > 0)" evaluates to false (when the Count IS 0)?

Welcome to the traps of negative boolean expression + bitwise operations on integers!

Yes, I could have written the expression as "(sl.Count = 0)", but alas, it was written as it was with "(NOT sl.Count > 0)".

To fix my error, the correct expression should have been (note the extra parentheses) :

if (NOT (sl.Count > 0)) then ShowMessage('String list is empty');

Now, about the "d'oh" :

The original "(NOT sl.Count > 0)" evaluated to false as

  1. sl.Count is 0,
  2. "NOT 0", since "0" is an integer, evaluates as a bitwise expression and returns -1,
  3. "-1" is NOT greater than 0, thus the final false result of my wrong expression!

Each day I learn something I already knew :) You?

Related:

Comments
October 21, 2011 at 8:21 am
(1) Alex says:

This can’t be fixed. Becaus then some expressions ‘ll evaluate wrong(which need NOT first).

October 22, 2011 at 10:40 pm
(2) Sebastian Jänicke says:

You wrote: “Of course, in my real-world code the entire boolean expression was much more complicated containing several AND’d and OR’d parts.”
Well, for me it seems that this was the real problem: the if expression was too complicated to have a quick overview.

If I combine multiple conditions in one if expression, I always set brackets everywhere even if they are not neccessary. Just to have clean code that everybody can read easily later. And if there are more than very few conditions, I put them in well named variables and use these inside the if expression.

So I never ran into this issue, but of course I am aware of it.

October 23, 2011 at 4:15 pm
(3) ˇarko Gajić says:

@Sebastian, the real-world expression contained several well bracketed parts (readable), then I added “(NOT sl.Count > 0)” and it stopped working. Happens.

October 25, 2011 at 4:59 pm
(4) Robert Oschler says:

var programmersPain: Extended;

begin
programmersPain :=
AbsDistance(
intendedFunction,
actualFunction) * (1 / Max(NumHoursTillDeadline, 0.001));
end;

// Note, the constant 0.001 was added to the Max() function in the denominator because once the number of hours left on the project is less than 1, the programmer’s pain approaches infinity asymptotically. And to avoid a divide by zero Exception of course. :)

October 25, 2011 at 5:36 pm
(5) Stephen says:

One of the reasons I like Delphi in my bigger projects.

When I use C I sometimes forget to use == for the equivilance. I found a bug recently from a 7 year old program I wrote

if (ErrLevel=0) // no error so continue
{

}

needless to say my ErrLevel was alway 0 and the condition always true

October 28, 2011 at 8:12 am
(6) Silver Warior says:

As far as I know the combination “if not” is only used when you are specifying booleand variables as conditions. This enalbes you to write “if MyBoolVar true then” easier as just “if not MyBoolVar then”. Both off theese examples excutes code when MyBoolVar is false.

Leave a Comment

Line and paragraph breaks are automatic. Some HTML allowed: <a href="" title="">, <b>, <i>, <strike>

©2014 About.com. All rights reserved.