Prefer Multiline if

C-family languages including Java, C#, and C++ do not require braces around single line blocks. For example, this is a legal loop:

for (int i=0; i < args.length; i++) process(args[i]);

So’s this:

for (int i=0; i < args.length; i++) 
    process(args[i]);

However both of these are very bad form, and lead to buggy code. All blocks in C-like languages should be explicitly delimited by braces across multiple lines in all cases. Here’s why:

The most dangerous form is a multiline block that doesn’t use braces. The problem is that when you start with this:

if (p.needsGiftWrapping()) 
    wrap(p);

sooner or later some programmer–perhaps you, perhaps someone else–is going to discover a need to add a second line. For example:

if (p.needsGiftWrapping()) 
    wrap(p);
   ribbon(p);

Bang! That code is now buggy. It looks like the if block applies to both statements, but in fact it only applies to one. The indentation is lying about the intent of the code. By contrast, this form is less dangerous:

if (p.needsGiftWrapping()) wrap(p);

In this example, it’s obvious to any programmer who comes along and adds a line, that they need to add braces too. It’s less likely to cause bugs down the road, but it should still be avoided, and here’s why.

The statement

if (p.needsGiftWrapping()) wrap(p);

is really two statements: one that calls needsGiftWrapping() and one that calls wrap(p). These are independent statements, and may need to be treated separately. In particular, you may want to mark a breakpoint on one and not the other. For instance, I sometimes like to put a breakpoint in the body of an if or for or while, just to make sure that this code is really being executed when I think it is. If the program doesn’t stop, then the code isn’t being executed; and I have a big clue where the bug is.

This is also important for code coverage tools. Most tools such as Cobertura measure the coverage of lines of code, not statements. Even if they measure lines of code coverage and statement coverage separately (and some tools do this) they still display the coverage with lines of code. This statement can be marked covered even if the body of the block is never entered:

if (p.needsGiftWrapping()) wrap(p);

However, if the block is rewritten like this:

if (p.needsGiftWrapping()) {
    wrap(p);
}

it now becomes obvious if the tests are never testing the case where p.needsGiftWrapping() returns true.

This applies equally to all block statements: if, for, while, do while, and any others you may encounter. I’m beginning to believe this is actually a special case of a general principle for C-like languages, and perhaps others:

Each line of source should contain exactly one statement

That is, avoid lines like this:

int i = 7, j = 18;

or

int i = j = 18;

Similarly, avoid the ?: operator.

if (a > b) {
  max = a;
}
else {
  max = b;
}

is easier to read than

max = a < b ? a : b;

For instance, did you even notice the bug in the above line? If the verbosity bothers you, try something like this instead:

max = Math.max(a, b);

The problem may reflect a misdesign in C-family languages. The compiler only pays attention to the semicolons and braces while ignoring the line breaks and indentation, but humans usually only pay attention to the line breaks and indentation while ignoring the semicolons and braces. This gives the code the opportunity to lie about what it’s really doing. Consequently we need to take extra care when writing in C, Java, C++, C#, etc. not to lie to ourselves. If you place exactly one statement on each source line, you can be reasonably confident the code isn’t lying to you, and you’ll have a much easier time debugging.

Compact code is fun, but it’s not maximally readable, and more lines don’t really cost you anything after the compiler is finished anyway. Save yourself the hassle and for 2009 resolve to put one statement on each line.

P.S.

If you want to comment on this article, remember that the <pre> tag is allowed in comments. Otherwise your point may get lost along with your indentation. :-)

23 Responses to “Prefer Multiline if”

  1. Kris Says:

    One statement per line… FORTRAN!

  2. Ricky Clarkson Says:

    To take this to its logical extreme:

    for(
    int i = 1;
    i < 10;
    i ++
    )
    {
    printf("%d\n", i);
    }

    I think we can probably agree that having the for (…) on one line is more readable than the above, but the above is better for code coverage inspection. This casts a little doubt on the sanity of writing code with code coverage inspection in mind (though you might write it that way while trying to work through code coverage problems).

    As for requiring braces for if statements and for loops, I think it would be better to require the programmer to use an editor that automatically indents code according to its significance, rather than to enforce a ‘blocky’ code appearance to avoid problems caused by not indenting code according to significance.

    Also, I found your if statement harder to read than the nearly-equal ternary operator use, and found the bug in it harder to spot as an if statement; there was too much around obscuring the meaning.

  3. Elliotte Rusty Harold Says:

    The for loop is a corner case. You certainly could cut that down. Your extreme is too extreme. This provides all the advantages:

    for (int i = 1;
          i < 10;
          i++) {

    That’s three lines shorter but still has each statement on a line by itself. I have seen this form used in real code, and used to consider it strange; but now I’m beginning to see the point. I do suspect that with very simple for loops like this one that merely increment a counter variable, then you might as well put it on a single line. However for more complex for loops, the mutline synatx works well. For example,

    for (String s = in.readLine();
          s != null;
          s = in.readLine()) {

    And of course anything substantially more complex than that should likely be split across multiple lines anyway, purely reasons of line length.

  4. James Iry Says:

    It’s sad that code coverage tools can’t make a simple distinction between lines and statements/expressions. Instead of writing code that feeds our tools, shouldn’t we fix the tools?

    And look at the price of skipping the ternary operator (in Java, but translate to your C language of choice using const pointers or whatever).

    final Foo x = p ? t : f;

    vs

    Foo x = null;
    if (p) {
    x = t;
    } else {
    x = f;
    }

    I’ve had to change an immutable variable to a mutable one and introduced null along with, in more complicated code, the possibility of null pointer issues. An alternative is

    Foo x = f;
    if (p) {
    x = t;
    }

    But I’m still using an unnecessary mutable variable, and if both f and t are expensive expressions to compute then this really isn’t a wise approach.

  5. Mike Says:

    That’s a fairly eloquent argument for Python syntax (demarcation of blocks by indent/dedent). That way you never have to deal with C/C++/Java/Perl bugs along the lines of “indented to mean X, but braced to mean Y”.

  6. Ricky Clarkson Says:

    Actually, James, you don’t have to make the variable mutable in that case. For Java and for C#, see the ‘definite assignment’ rules.

  7. Eric Says:

    As is almost always the case, programming involves opposing forces. Opposing the idea of always using {} for blocks and formatting a statement across multiple lines is an increase in visual noise and occupied vertical space. Reading code is harder when there is more of it to scroll through. A contrary view is to minimize the amount of vertical space, even to the point of almost never breaking lines (except in the case of lists of similar things)–most editors are capable of soft-indenting wrapped lines so this is actually a decent option. I’m not talking about Perl one-liners, but simply making each statement occupy one line.

    As for the introduction of bugs due to indentation errors, I think this is somewhat overblown. There are numerous syntactic errors that can occur in programming languages, we usually avoid these by experience, testing, and code reviews.

    Could it be that the time spent avoiding rare syntactic bugs and formatting lines to fit in 80 columns is simply wasted time? I suspect so, but I don’t know of any studies to back that up. I do know that I prefer to look at code which is clear and concise, and removing excess vertical space and braces helps to make that happen. This view is diametrically opposed to the one you are espousing, but one you might consider.

  8. John Cowan Says:

    I think you mean “at most one” rather than “exactly one”, unless you are also rejecting block comments, blank lines, and } on a line by itself.

  9. Bruce Boughton Says:

    For me, your arguments point to a failure of tools rather than coding style. Why can’t breakpoints be assigned to statements rather than lines? Surely that is more natural for the debugger. It seems to me that the window layout (breakpoint marker in margin) is what enforces this rule rather than the actual requirements of the debugger.

    As for coverage, there are three kinds of lies: lies, damned lies, and coverage.

  10. Farialima Says:

    Yet another issue that’s a non-issue in Python. As you said it yourself: Java is dead, long live python !

  11. Pinner Blinn Says:

    I don’t buy it. The “dangerous” example is an old chestnut from the beginning of C best practices. The “sooner or later” bug will never be a problem for a competent programmer. Yes, put in those braces for extra clarity, but if you want better assurance, don’t hire someone who doesn’t understand basic syntax to maintain your programs.

    It is, of course, good practice to try to make your program structure “readable” in the sense that the next person should not misinterpret the meaning. Code presentation can also enhance understanding of of the underlying algorithms, just as the readability of a book can be improved by a better layout.

    I have to take issue with the statement “humans usually only pay attention to the line breaks and indentation”. That seems like a pretty weak argument. Programmers are humans who are trained to pay attention to the details that matter in a computer language. Moreover, I think whitespace (including linebreaks and indentation) can be very useful in fostering readable presentation, while tying whitespace to language meaning removes this flexibility.

    For example, I sometimes use a code layout like the following:

       result = (logical expression)
                   ? (expression)
                   : (expression);

    In and of itself, the above template is not a panacea, but it is a tactic that can be used to present algorithmic information clearly and concisely, hopefully leading to more ready understanding. I’m glad that the “misdesign” of the language allows this possibility.

  12. Pinner Blinn Says:

    Hmmm… the pre tag did not preserve my indentation.

    As I wrote it, the “?” and the “:” should align under left parenthesis above.

  13. Russel Says:

    Firstly I agree with plain old fashioned common sense. But may I just add one thing to this discussion. Not all of us have perfect vision. Mine is within the definition of legally blind (but I do have a really nice monitor). So I’m going to tread on everyone’s toes by saying this:

    Please, line the braces up, like this:

    while (TRUE)
    {
    a statement;
    another statement;
    }

    It is a coding style that has served me well and it is damn frustrating that every time I go to read someone else’s code, I end up having to reformat it so I can read it. Yes, I even do this.

    if (this is true)
    {
    do something;
    }
    else
    {
    do something else;
    }

    Time after time I find programming editors will fight you on this. But it is the only way I can read code without getting hopelessly lost! Yes, I know I’m probably tilting at windmills. But you know where I first saw this coding style? It was in the Amiga ROM Kernel Manual. I liked those guys. It would be nice if it had caught on.

    Oh, and btw, anyone caught using the p?t:f; shorthand will be shot on sight as far as I’m concerned :)

  14. Pete Kirkham Says:

    Just run it through your favourite pretty printer and don’t worry about it.

  15. Pepito Says:

    Well, I often learn something coming here, but today’s was unexpected. I’d never heard of this quite useful tag.

  16. Ned Batchelder Says:

    The “computers look at semicolons, people look at indentation” idea is exactly what I tell people who chafe at Python’s indentation-based blocks. I’m not sure it convinces them, but it is the best reason I know for prefering Python’s way.

  17. pete Says:

    Here is why I like to always use braces:

    if (a<b)
    System.out.println(“a: “+a);
    max = a;

  18. firefight Says:

    Another reason to have one statement per line is debugging: stepping through code in a debugger and reading a stack trace make so much more sense when you only have one line per code. Otherwise, where exactly was that NullPointerException thrown?

  19. Klaus Says:

    Yeah, the Python idea is nice … but I am always afraid enough when I
    see how some C++/Java code (created with emacs) looks like in
    my other editors that have no clue about the emacs-style indenting
    with tabs.

    I am not sure if I want to find out what happens when a lot of people
    are using different editors on the same python file.

    Spaces/tabs are easily inserted/removed from a file. I really dont like
    the idea that such changes can affect the semantics of your program.

  20. Pinner Blinn Says:

    Klaus,

    For precise representation of indents, emacs users should convert tabs to spaces upon saving.
    That is, in the .emacs file, include something like:

    (defun better-save ()
    (untabify (point-min) (point-max)))

    (add-hook ‘write-file-hooks ‘better-save)

    No shared source anywhere should include ascii tabs.

  21. Frank Berger Says:

    do you really think

    if (a > b) {
    max = a;
    }
    else {
    max = b;
    }

    is easier to read than

    max = a < b ? a : b;???

    1.) ?: is much less stuff to read so much easier to grasp
    2.) In the verbose form I have to look at both assignments to see that they both are assignments to the same variable.

    Naturally the Math.max is the best approach here but in other cases I appreciate the ?: as concise and clear.

    look at this:

    state = x < z ? “perfectly well” : “critical condition” ;

    if (x < z) {
    state = “perfectly well”;
    }
    else {
    err = “critical condition”;
    }

    This only holds true with simple ?: . Nested ?: are completely unreadable.

  22. Bridget Says:

    Forthesamereasonthatthisishardtoread,
    whitespace makes anything (including code) more readable. It is why we put spaces between words and why short paragraphs are easier to digest.

    Code isn’t prose, but we humans still need to read it.

  23. Russell Bateman Says:

    A generation ago, outside the hands of a few indentured Unix old-timers, I thought the theoretical programming style community had just about laid to rest the practice of orphaning the left brace.

    Arriving in Javaland, I see that this unsightly practice is alive, well and pervasive. Even old colleagues who wrote C code with aligned left and right braces (just as God does) have shriveled in the face of Eclipse’s and the Java community’s insistence that you modify editor behavior (which I gladly surrender myself to doing) or go digging for a preferences file (ditto).

    It’s a second wave of horror visited upon us a generation after Brief encouraged some of the most egregious indentation practices possible. (I, on the other hand, never abandoned vi for Brief and neither did God who must also consequently eschew Eclipse, something I’m unable to do.)

    Yes, I think some of you have lost your way.

    Anyway, a lot, but not all of the original thesis are doctrines I’ve long practiced and agree with. I also still practice, as a few others admit here, my beloved ternary expressions.

Leave a Reply