Friday, September 2, 2011

"Don't do what Donny Don't does"

Thank to Evan Hughes for pointing out this paper: Conditional statements, looping constructs, and program comprehension: an experimental study.

Not surprisingly, negative conditions are more difficult to understand than positive conditions.

I always try to write conditions to be positive. Sometimes, I'll even include an empty 'if' block so that I can put code in the 'else' block instead of using a negative condition:

   if (isInRange(value)) {
      // expected case; do nothing
   } else {
      throw new OutOfRangeException(value);
   }

I haven't read the full paper, so maybe the researchers answered my next question: is the problem exacerbated by the syntax for negative conditions used in C-like languages? I find that the '!' operator uses very little horizontal space, making it less noticeable than other unary operators such as '~' or '*'.

e.g. would this statement:

   if (!isInRange(value)) { ...

be more obvious if it were written like this?

   if (not isInRange(value)) { ...

3 comments:

  1. As always, very nice post Peter. I've not read the paper you mention, but I wanted to comment that I have a coding style that is not very common, and that often receives negative comments, at least at first! Over time I have won a few converts, for the reasons outlined below.

    Here's what I do when I have a negative if-clause:

    if (isInRange(value) == false) { ...

    Others reject its verbosity, and while I cannot argue that it is verbose, I don't see the problem. At its core, software development is all about the communication of a solution to a problem, so if extra verbosity improves communication, then so be it.

    My quirky style is helpful since in addition to being verbose, it clearly communicates the expected value on the left, and the right, of the equality operator. It is even more valuable, in my opinion, when an additional temporary is used, for example:

    boolean valid = isInRange(value);
    ...
    if (valid == false) { ...

    The explicit equality comparison of 'valid' to 'false' is particular helpful when debugging (possibly complicated) code (possibly not written by you) since the debugger display the value of the temporary 'valid', making it trivial to mentally perform the equality comparison to 'false' as you step through the code. This, of course, is particularly important when debugging at 3am and you need to have been done already!

    ReplyDelete
  2. I guess it comes down to personal preference and style, but I have to say it drives me crazy to see a boolean being compared to true or false like this. I actually find this more confusing when I see it because that's not how we formulate questions in english. I.e., we would say, "if the value is not in range", rather than "If the value is in range is equal to false". Or, "Do you want to go to the store", rather than "Is do you want to go to the store equal to true?"

    Having said that, I agree with both of you that readability and comprehension are extremely important and worth a little extra verbosity. Although it's not always possible, my ideal solution in this case would be to use a more expressive function name:

    if (isOutOfRange(value))
    throw new OutOfRangeException(value);

    ReplyDelete
  3. Yes, John, you are right. Good names are important, and always challenging to think of! I first stopped using the 'not' operator (!) back when I used Smalltalk where the font is often proportionally spaced, resulting in a very skinny exclamation point that is very hard to see! So I favored other approaches, which I continued to use when programming in Java.

    The other challenge, of course, is the double negative, or the complicated boolean expression consisting of many AND'ed and OR'ed expressions, all of which must be true (or false) for the particular if-block, else-block or while-block to be evaluated.

    This reminds me of the peculiar habit of switching the lvalue and rvalue, so instead of:

    if (x == null)...

    you end up with:

    if (null == x)...

    This one is common in ond-time C programmers that are terrified of accidentally typing:

    if (x = null)...

    which is legal in C and a very difficult bug to find. The opposite is illegal in both C and Java:

    if (null = x)...

    Since null can never be an lvalue.

    At the end of the day I remain open minded and am always happy to be convinced that my coding style can be improved. Now, what color are we going to paint that bike shed? :-)

    ReplyDelete