Thursday, June 11, 2009

Say what you mean

In code it's very important to say exactly what you mean and mean what you say.

Why ?

I just happened to reproduce and fix a bug in the IDE that was the result of code not being explicit about what was intended.

The particular bit of code was in a listbox cellkeydown handler and read

If me.ListIndex <> -1 and key = SpecialChars.EnterChar or key = SpecialChars.ReturnChar then

dim tag as string = me.CellTag(me.Listindex, 0)

But this was throwing an out-of- bounds exception sometimes when you'd press return. But, why?

If you look at the expression you will see that the boolean operators AND has a higher precedence
than OR. This means that
me.ListIndex <> -1 and key = SpecialChars.EnterChar
gets evaluated BEFORE the OR.
This expression turns out to behave as though you wrote

((me.ListIndex <> -1) AND (key = SpecialChars.EnterChar)) or (key = SpecialChars.ReturnChar)

The end result was IF you pressed return the code for the THEN portion WOULD execute when it should not and this caused the out of bounds exception.

What this expression should have said was:

(me.ListIndex <> -1) AND ((key = SpecialChars.EnterChar)) or (key = SpecialChars.ReturnChar))

So the listindex had to be <> -1 before the code in the then would execute.

A very small change, but a very big difference.

Be clear and be safe out there :P

9 comments:

Anonymous said...

Norm,

Actually I don't think there is any need for so many parentheses- and more than necessary IMO makes things harder to read by humans.

How I would write that I think is equally unambiguous but more easily readable:

IF me.ListIndex <> -1 AND (key = SpecialChars.EnterChar OR key = SpecialChars.ReturnChar)

- Karen

Kelsey said...

I agree with Karen; plus the example provided contains one too many right parentheses -- adding to the confusion.

Roger said...

Hmm, I think I disagree. If you use the extra set of parentheses you won't have to think about precedence at all, and it is clear immediately as to what is evaluated first. To me this is less confusing.

kirkgray said...

I don't bounce between languages as often these days as I did in my youth. And rules of precedence seem much more uniform between languages than they were when I was cutting my teeth.

But I got in the habit of parenthesizing everything completely (as in Norman's final example) because as a young programmer I was language fickle and ran into hard to find bugs because of this very problem.

I've found comprehensive parenthesizing to be quite helpful in writing, debugging, and in reading the code down the line. I also find others' code without complete parentheses to be unsettling -- there's always a question in my mind as to whether it works as intended (or instead, as written).

kirkgray said...

Also, complete parentheses in this example reassures me I'm using logical AND and OR rather than bitwise operations.

(I'm a big believer that logical and bitwise operators should have different names, but that ship has sailed in Realland and we are where we are.)

Eric said...

I've programmed using several languages, COBOL, Fortran, Pascal, BASIC, REALbasic, UNISYS LINC, ADS, Prolog and LISP - so I know a thing or two about parentheses! - and I have to agree with Karen.

As soon as I saw the code in error I knew what the fault was. Always put parentheses around your OR conditions, and try not to mix ANDs and ORs too much. Better two if statements than something you can't easily read or debug.

Eric.

Norman said...

The reason I parenthesize extensively - which one has higher precedence =, <>, AND or OR ?

The full parentheses make it unambiguous as to how I want it evaluated (regardless of what the compiler thinks) and I don't have to even think about precedence when looking at it.

Kannan said...

It would be great if you give the solution for the vb.net code equivalent code in RealBasic. I am new in RB program.

Char.ConvertToUtf32(name, count)
Char.ConvertFromUtf32(number)

Waiting for your early reply. Its very very urgent.

Thanks in advance.

Rhywun said...

Totally agree--you cannot have too many parentheses :)