Current version

v1.10.4 (stable)

Navigation

Main page
Archived news
Downloads
Documentation
   Capture
   Compiling
   Processing
   Crashes
Features
Filters
Plugin SDK
Knowledge base
Contact info
 
Other projects
   Altirra

Archives

Blog Archive

Religious issues (for programmers)

Anyone who's been coding C/C++ long enough in a group environment knows that there are two topics that should be treated like kryptonite:

If you're smart, you try not to bring these up for discussion unless you have a disaster looming or you have a more amiable/senior group than average. I'm not kidding when I say this. If you get a group of random C/C++ programmers together into a team and bring up one of these issues you're guaranteed to have a long, protracted, bloody argument on your hands. You'll have people arguing about which one is more productive, why one style is better than the other, how everything should be changed to use one of them, why the other style is bad, enforcing style guidelines, etc. And it'll go on, and on, and on.

It's not that people want anarchy -- most will agree on the benefits of consistency -- but the vehement arguments for choosing one style over another can be awe-inspiring.

Now, after hearing all of the arguments, you'll probably come out thinking that one style is indeed superior over the other, for various scientific-sounding reasons. Let me share a secret with you: they're all largely BS. The better and more experienced a programmer is, the more likely he'll be able to read and write a wide variety of styles. The mark of an inexperienced programmer is one who believes that he truly will not be able to write and maintain a working line of code unless the brace is positioned on line 7, column 17. The reason for preferring a particular style? Most likely just either (a) what he learned, or (b) what he's been using (or forced to use) in the past few years. That's basically it.

I won't claim to have transcended this phenomenon myself; I use the style that I do largely just because I learned C from K&R second edition. I have evolved it slightly over time, though.

Tab styles

Tabbing refers to indentation placed at the beginning of a line, where indentation is used to help indicate structure:

while video frames are left:
    fetch a video frame
    decode it
    for each video filter:
        run the video filter
    compress the video frame
    write it out to disk

There are two types of tabs. Hard tabs are ASCII code 09 and indent to the next tab stop, regardless of the number of character cells to the tab stop. Editors generally treat hard tabs as single characters for movement purposes, so that hitting right when you're in front of a tab moves you all the way to the tab stop. Soft tabs are tabs emulated using spaces -- the editor inserts as many spaces as are necessary to reach the tab stop.

I don't have a particular preference for either type of tab, and have coded in both styles without problems.

Hard tabs have the advantages that you can move across indentation faster if you use single-cell movement keys and have to fuss with them less often in order to line things up after an edit. They have the downsides that changing the tab size in the editor changes the arrangement of all of the code, and you have less flexibility in lining things up since you can only indent to tab stops. Hard tabs also have the dubious advantage of working when you are using a proportional font -- but that is a practice that is best avoided unless you are good at evading angry coworkers who found that your indentation only looks correct with the Wingdings 12 font and ClearType disabled.

Spacing done with soft tabs can be finely adjusted just by adding or removing spaces, which is nice. The code arrangement also won't turn into a mess if you happen to change the tab size. If you do a bunch of replaces in nicely lined up tables or initializer lists, though, you're likely to have to spend a lot of time fussing with the spacing again, and unlike hard tabs, the effect of hitting tab in the middle of indentation is a bit less predictable. When people aren't too careful about this, it's not unusual to see a few lines with indentation that's +/-1 off, which is a bit harder to notice than if you're off by an entire tab stop. But at least you don't have non-space characters hidden where you don't expect them.

You also have the choice of tab size. Common sizes are 2, 4, and 8, and occasionally you'll see really strange widths like 3. There aren't any good arguments for any of them, aside from 8 being the original tab size on old terminals, and that isn't a very good one. Generally the reason behind existing usage of a particular tab size is that someone has a habit of indenting way too much, too little, or just right for their editor width, or does/doesn't place a space before the parentheses in an if().

All in all, I don't have a real problem with either mode. VirtualDub is coded using hard tabs at width 4, but mainly just because that was the default in Visual C++ 4.0. I used to use 8 when I used BRIEF and Turbo C++ in DOS. What you definitely don't want is files that have a mix of both, as they're very unpleasant to edit. In Visual C++ 6.0, the useful Edit.WTFTabModeDidTheyUse command is bound to Ctrl+Shift+8 by default.

The one hard rule I have here is that C# code is always, always indented using spaces... but the reason for that is because I got burned by the Visual C# editor, which reformats code blocks automatically, and in certain scenarios, is lame enough to convert spaces to tabs in the middle of string literals and even single spaces into tabs.

Braces

Braces -- { and } -- are symbols used by languages similar to C to denote blocks of statements and initializers. Some languages, like Python, can look at indentation directly to determine the scope of a loop, but C/C++ use braces entirely for this purpose, with whitespace only being a convention for readability. There are several styles for brace placement. I won't bother to list all of them -- you can consult Wikipedia or the Jargon File for exhaustive lists -- but I will describe the two common ones I encounter. The first is same-line (often called K&R):

if (condition) {
    DoSomething();
}

...and the second is next-line (a.k.a. BSD or Allman):

if (condition)
{
    DoSomething();
}

Proponents of the first style say that the opening brace is best considered part of the control structure; those who like the second proclaim the benefits of matching brace position.

As you might have guessed, I use the first formulation. Well, most of the time. Write C++ long enough and you'll find that neither style works all of the time; for me, a slight mix of the two works better. For instance, I generally write functions like this:

void DoSomething() {
}

This doesn't work so well for class constructors, though, which I write in this manner:

MyClass::MyClass()
    : member1(0)
    , member2(0)
{
}

Why the goofy style, with the colon and comma at the beginning? It avoids having the oddball initializer at the end with no comma, which otherwise is a nice place to have source code control conflicts during integration, and also prevents disaster when people try to wrap conditionals with #ifdefs (which is a bad practice, but which is occasionally necessary).

I also like moving the brace to the next line when an if() condition gets a bit big:

if (condition1 &&
    condition2 &&
    condition3)
{
}

However, there are two disasters that I've found with this style. One is struct definition with initialization:

struct
{
    float f;
    int i;
}
fastConverter=
{
    val + 12582912.0f    // 2^22 + 2^23, the magic fast float-to-int value
};

...and the other is do...while() loops.

do
{
    ...
}
while(condition); // UGH

There's also the question of when to use and to omit braces. Omitting braces can be hazardous, especially when you see examples like this:

if (condition)
    // Handle special case
    DoSpecialCase();

On the other hand:

if (i < 0)
{
    i = 0;
}
else if (i > limit)
{
    i = limit;
}

...occupies too much space for my tastes, given its low complexity. The braces aren't any more worthwhile when put on the same line, either. For really simple statements, I'd just rather do this:

if (exit condition)
    break;

and save the strong layout for code that needs more mindshare. Makes the loops stand out more.

As you've noticed, most of the reasons for my brace preferences above are due to other stylistic choices I've made. None of them really stand well on their own.

Don't give in to style hate. Embrance multiwhitespaceism and be flexible to the situation at hand.

Comments

This blog was originally open for comments when this entry was first posted, but was later closed and then removed due to spam and after a migration away from the original blog software. Unfortunately, it would have been a lot of work to reformat the comments to republish them. The author thanks everyone who posted comments and added to the discussion.