What does style look like, part 3


When we last left the code we were looking at, it looked like:

#include "list.h"
main(C cArg, SZ rgszArg[]) {
    I iNode, cNodes = atoi(rgszArg[1]), cNodesToSkip = atoi(rgszArg[2]);
    PNODE pnodeT, pnodeCur;
    InitNodes(cNodes);
    for (iNode = 2, pnodeCur = PnodeNew(1); iNode <= cNodes ; iNode++) {
        pnodeT = PnodeNew(i);
        InsertNext(pnodeCur, pnodeT);
        pnodeCur = pnodeT;
    }
    while (pnodeCur != PnodeNext(x)) {
        for (iNode = 1; iNode < cNodesToSkip ; iNode++)
            pnodeCur = PnodeNext(pnodeCur);
        FreeNode(PnodeDeleteNext(pnodeCur));
    }
    printf("%d\n", Item(nodeCur));
}

This time, let’s consider a different indentation style:  Braces after the expression, every optional brace included (modified BSD)

#include "list.h"
main(C cArg, SZ rgszArg[])
{
    I iNode, cNodes = atoi(rgszArg[1]), cNodesToSkip = atoi(rgszArg[2]);
    PNODE pnodeT, pnodeCur;
    InitNodes(cNodes);
    for (iNode = 2, pnodeCur = PnodeNew(1); iNode <= cNodes ; iNode++)
    {
        pnodeT = PnodeNew(i);
        InsertNext(pnodeCur, pnodeT);
        pnodeCur = pnodeT;
    }
    while (pnodeCur != PnodeNext(x))
    {
        for (iNode = 1; iNode < cNodesToSkip ; iNode++)
        {
            pnodeCur = PnodeNext(pnodeCur);
        }
        FreeNode(PnodeDeleteNext(pnodeCur));
    }
    printf("%d\n", Item(nodeCur));
}

That’s a fascinating difference.  Moving the braces down to the next line opens the code up quite a bit, making it easier to see how the code is structured.  Next, what happens with the declarations – the declaration of iNode,cNodes, and cNodesToSkip is smushed together, lets split them out into separate lines.

#include "list.h"
main(C cArg, SZ rgszArg[])
{
    I iNode;
    I cNodes = atoi(rgszArg[1]);
    I cNodesToSkip = atoi(rgszArg[2]);
    PNODE pnodeT;
    PNODE pnodeCur;
    InitNodes(cNodes);
    for (iNode = 2, pnodeCur = PnodeNew(1); iNode <= cNodes ; iNode++)
    {
        pnodeT = PnodeNew(i);
        InsertNext(pnodeCur, pnodeT);
        pnodeCur = pnodeT;
    }
    while (pnodeCur != PnodeNext(x))
    {
        for (iNode = 1; iNode < cNodesToSkip ; iNode++)
        {
            pnodeCur = PnodeNext(pnodeCur);
        }
        FreeNode(PnodeDeleteNext(pnodeCur));
    }
    printf("%d\n", Item(nodeCur));
}

Again, this helps a bit, but not a lot.  What about other bracing styles?

#include "list.h"
main(C cArg, SZ rgszArg[])
{
        I iNode;
        I cNodes = atoi(rgszArg[1]);
        I cNodesToSkip = atoi(rgszArg[2]);
        PNODE pnodeT;
        PNODE pnodeCur;
        InitNodes(cNodes);
        for (iNode = 2, pnodeCur = PnodeNew(1); iNode <= cNodes ; iNode++)
        {
                pnodeT = PnodeNew(i);
                InsertNext(pnodeCur, pnodeT);
                pnodeCur = pnodeT;
        }
        while (pnodeCur != PnodeNext(x))
        {
                for (iNode = 1; iNode < cNodesToSkip ; iNode++)
                {
                        pnodeCur = PnodeNext(pnodeCur);
                }
                FreeNode(PnodeDeleteNext(pnodeCur));
        }
        printf("%d\n", Item(nodeCur));
}

8 character indents stretch the code out a bunch, but they don’t effect the overall effect.  How about a variant of 8 char indents?

#include "list.h"
main(C cArg, SZ rgszArg[])
    {
        I iNode;
        I cNodes = atoi(rgszArg[1]);
        I cNodesToSkip = atoi(rgszArg[2]);
        PNODE pnodeT;
        PNODE pnodeCur;
        InitNodes(cNodes);
        for (iNode = 2, pnodeCur = PnodeNew(1); iNode <= cNodes ; iNode++)
            {
                pnodeT = PnodeNew(i);
                InsertNext(pnodeCur, pnodeT);
                pnodeCur = pnodeT;
            }
        while (pnodeCur != PnodeNext(x))
            {
                for (iNode = 1; iNode < cNodesToSkip ; iNode++)
                    {
                        pnodeCur = PnodeNext(pnodeCur);
                    }
                FreeNode(PnodeDeleteNext(pnodeCur));
            }
        printf("%d\n", Item(nodeCur));
    }

This one’s kinda interesting.  The braces are now more clearly laid out.  On the other hand, it’s a bit disconcerting to have the “printf” hanging out on its own.  Personally, I’m not too happy with this one.

How about the “braces appear on the same line as the code they wrap”?

#include "list.h"
main(C cArg, SZ rgszArg[])
{
    I iNode;
    I cNodes = atoi(rgszArg[1]);
    I cNodesToSkip = atoi(rgszArg[2]);
    PNODE pnodeT;
    PNODE pnodeCur;
    InitNodes(cNodes);
    for (iNode = 2, pnodeCur = PnodeNew(1); iNode <= cNodes ; iNode++)
        {
        pnodeT = PnodeNew(i);
        InsertNext(pnodeCur, pnodeT);
        pnodeCur = pnodeT;
        }
    while (pnodeCur != PnodeNext(x))
        {
        for (iNode = 1; iNode < cNodesToSkip ; iNode++)
            {
            pnodeCur = PnodeNext(pnodeCur);
            }
        FreeNode(PnodeDeleteNext(pnodeCur));
        }
    printf("%d\n", Item(nodeCur));
}

An interesting variant.  I don’t know if it’s an improvement, but…

Just for grins, the style of a senior developer within Microsoft:

#include "list.h"
main(C cArg, SZ rgszArg[])
{
    I iNode;
    I cNodes = atoi(rgszArg[1]);
    I cNodesToSkip = atoi(rgszArg[2]);
    PNODE pnodeT;
    PNODE pnodeCur;
    InitNodes(cNodes);
    for (iNode = 2, pnodeCur = PnodeNew(1); iNode <= cNodes ; iNode++) {
        pnodeT = PnodeNew(i);
        InsertNext(pnodeCur, pnodeT);
        pnodeCur = pnodeT;
        }
    while (pnodeCur != PnodeNext(x)) {
        for (iNode = 1; iNode < cNodesToSkip ; iNode++) {
            pnodeCur = PnodeNext(pnodeCur);
            }
        FreeNode(PnodeDeleteNext(pnodeCur));
        }
    printf("%d\n", Item(nodeCur));
    }

In this style, the opening brace goes with the if/while/for loop, but the closing brace goes with the code at that level of indentation.  Again, it’s an “interesting” choice.

Tomorrow, we add comments.  That’ll help a bundle towards helping this out.

 

Comments (23)

  1. James H. says:

    Of those, my style is most like your modified BSD style.

    For instance (pardon my Java… I’ve got it on the brain at the moment..):

    import javax.swing.*;

    public class Sample

    {

    public Sample ()

    {

    // Blah blah blah

    }

    public static void main ( String[] args )

    {

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

    {

    System.out.println ( args[ i ] );

    }

    }

    }

    I’m all about the white space. I think it makes my code easy to read. Also, notice that in Java I used the square array brackets on the variable type, and not the name. To me, this helps me know that much faster that I’m dealing with an array.

    The only other "real" language I know is C, and my style is almost identical.

    The only problem is that when I have to hand in assignments (Still a student), this style takes up a LOT of paper and sometimes is butchered by print margins.

  2. Mike Dunn says:

    "braces appear on the same line as the code they wrap" is the only way to fly. Not indenting the braces is ok too, but it’s just not the style I use or am used to.

    Having the opening brace on the same line as the if/for/while is definitely worse because when you’re looking at a } it’s *much* harder to quickly scan the code and find the matching {. Sure, you can hit ^] in VC to find it, but you don’t always have VC at your disposal.

    Having each { and } on its own line also gives some much-needed vertical whitespace. There’s nothing I hate more than seeing a big ol’ block of code with no vertical spacing to indicate logical breaks in the logic flow.

  3. Funny you should mention that Bjorn, that change comes up during the comments discussion tomorrow :)

  4. Björn Roth says:

    Agreed. I would also punch a newline after the for- and while-blocks to make them stand out further.

  5. Srdjan says:

    My style is ‘modified BSD’ — as other readers suggest, it gives you more vertical white space (I would put another one blank like after variables’ declarations)…

  6. David Candy says:

    You’re all wimps with this structured code. Surveycraft is basic pseudocode (as real survercraft variables are names after the line number created on)

    10 10=input "enter something"

    20 20=input "enter something"

    30 msgbox 10

    40 msgbox 20

    50

    15 If 10 = "dog" then goto 30

    35 If 20 = "" then goto 50

    Now this is real coding style. Seperating actions from flow. Makes C coding style debates seem really minor. Lucky it has gone out of fashion.

  7. Skywing says:

    BTW, it’s not legal in either C++ or C99 to leave out the ‘int’ return type for main (though it is legal to omit ‘return’)…

  8. You’re right Skywing, but that’s the sample as it appears in the book, so…

  9. Mike Dimmick says:

    Mine’s ‘modified BSD’, but I normally put a blank line before a new control structure (unless right after an opening brace), after closing a control structure (unless right before a closing brace), and between declarations and code, so I’d insert a blank line after line 1, 8, 9, 15, 21 and 23 (of your third example, where you put each declaration on its own line).

    This style really emphasises control structure. I also put spaces inside parentheses unless the parens indicate a cast. In C languages, I always put a space between a control keyword and the controlled expression but never between a function call and its parameter list [e.g. if ( x ) but f( x )]. OK, it takes a lot of lines – and I follow the rule of not allowing a function to take more than a couple of screenfuls, but then a screenful is a lot of lines on current monitors. Personally I can’t stand horizontal scrolling; if I must break a function call, for example, I’ll normally break after the opening paren and after every argument (i.e. either all-on-one-line or one-argument-per-line).

  10. Michael says:

    OK, I figured we could ask the ‘K’ of K&R and maybe get a deep response.

    ——————-

    From: Brian Kernighan

    Sent: Thursday, November 11, 2004 5:58 PM

    To: Michael

    Subject: Re: Braces, indention, etc.

    i just copied what ken and dennis did, if i remember right. nothing very deep.

    ——————-

    OK, nothing good there. I’ll see if I can get Ken to offer up something…

  11. > Just for grins, the style of a senior

    > developer within Microsoft

    Are you sure he indented by 4 columns not 3?

    IBM PL/I manuals put the "DO;" at the end of a line as in OTBS, but indented the "END;" at the same level as the nested statements instead of outdenting it back to the "IF" or "WHILE" or whatever initiated the do-group. If I recall correctly, those same IBM PL/I manuals indented code by multiples of 3 columns. (And oh yeah, don’t forget to leave 1 blank in column 1 of every line unless you’re going to submit a compile listing to the International Obfuscated PL/I Coding Contest.)

    Unfortunately I don’t know MULTICS PL/I style. Can anyone else say?

  12. I’m pretty sure it was 4 (although I may be wrong, I’m resurrecting his style from memory, the code he worked on no longer displays this style). To my knowledge, this developer never worked in PL/I.

    Ah, found some code that hadn’t been "cleaned" up. Yup, it was 4.

  13. Phaeron says:

    I’ve seen some style guides (SGI?) that specify #1 for control structures but #2 for functions.

    The most unique style I ever had to match was:

    if(condition){

    doSomething();

    }

    else{

    doSomethingElse();

    }

    It wasn’t hard to pick up given a K&R background, but it looked very strange the first time I saw it.

  14. Travis says:

    I vote for modified BSD or the one following "lets split them (the declarations) out into separate lines." Opening up the code, like you say, makes it easier to see what’s going on with a glance, rather than having to read it. This reason (glance vs. read) is why I like languages with C-style syntax over languanges with VB-style syntax. It’s just easier to see what’s going on.

  15. Greg, you’re confusing the content with the style. The content is irrelevant, it’s the style that counts.

    Maybe I should have written up a function that did absolutely nothing, but for better or for worse, I chose a real example.

  16. I’m a modified BSD man when it comes to C, but it looks like the main reason why this code is so dog-ugly (I mean besides the whole Hungarian mess) is that it should’ve been written in an altogether different language. Something with native lists and higher-order functions please.

  17. I can understand why you want to separate style from content, but is it always that easy? Is style only concerned with indenting and carriage returns? I would view choosing i++ vs. i+=1 vs. i=i+1 to be a style issue. Also consider making a speed vs. elegance trade-off. Is that not an issue of style? As you stated on Tuesday, "A good coding style should result in high quality self-documented code that is esthetically pleasing to look at." It might be interesting to discuss these ideas, even if you don’t agree that these are issues of ‘style’.

  18. No, it’s not always that easy. But for the purposes of this discussion, I don’t want to get into whether or not a particular piece of code should be written with a different library (or a different language).

    The problem is that external constraints prevent many of those choices (for example, using STL in a windows device driver is invariably a bad idea), so while it might be cleaner to use STL, it might not be possible.

    Whereas these articles are language and situation neutral (or at least I’m trying to make them so).

  19. 11/12/2004 11:06 AM Greg Buchholz

    > I would view choosing i++ vs. i+=1 vs. i=i+1

    > to be a style issue.

    Close. ++i vs. i+=1 vs. i=i+1 is a style issue. (Also the possibility of inserting whitespace into any or all of those is a style issue.[*]) But i++ yields a different answer. Of course it’s also a style issue whether to ever write code that directly uses the result of either ++i or i++, but when reading code you’d better be aware that they yield different answers.

    [* Actually it wasn’t always a style issue. Operator += used to be operator =+ which didn’t matter much because there was no unary +, but operator =- used to be operator =- and it mattered. If you wanted to do a = – b then you could omit the space between – and b but you couldn’t omit the space between = and -. This resulted in enough bugs that DMR changed the language. This change was only needed for code/coders who didn’t use whitespace where it was necessary. This also gave me an opportunity to mouth off at DMR in comp.lang.c around 15 years ago. In response to someone else’s posting, he posted "whitespace is your friend". I retorted that if he really believed that then he wouldn’t have changed =- to -=.]

  20. Nick says:

    First "modified BSD" of course; minus the Hungarian, and you’re getting somewhere :)