Curly Braces – the holy war
I sense I’m spurring a holy war discussion when I raise the issue, but some have asked why I code with curly braces on the same line rather than a new line.
My answer is simple: readability.
The goal with any code is not solely to accomplish the problem at hand, but to make the code legible for the casual reader who will come by it later on. Maintainable code is written legibly.
As an example, consider the Visual Basic type “variant”. It defines a variable as “something”. Um, gee, thanks.
Dim myvar as Variant
myvar = "1"
myvar = 1
myvar = 1.0
myvar = Workbook.Worksheets[0]
What is myvar? Is it an int? A string? A float? An object? None of the above? Is it a value type? Is it a reference type? Maintaining code that use variants is a nightmare.
Visual Basic has quite a few more features that make code difficult to maintain, but leaving them aside, the entire concept of variant is undescriptive. It does not descriptively explain its intended use. Though syntactically correct, it does not document itself very well. It is “write only” code.
Curly braces in all C-style languages define code blocks much more susinctly than Visual Basic’s “End If”. You can casually glance through code, watch curly braces open and close, and know you’ve changed a variable’s scope. However, curly braces have a dark side.
Curly braces can define two sets of behavior. Coding with { on a new line for both behaviors does not specifically define which use you are looking for. Only by looking to code around the { do you know what the curly brace really does.
Consider the following:
{
defines the start of a scope and }
defines the end of a scope. Coders define blocks inside {
and }
to define scope of variables. They document the scope by indenting contained code with tabs:
int i = 0;
{
int j = 1;
}
// j doesn't exist here
// i does
{
string j = “value”;
// this j has a different meaning and purpose than the j above
}
{
and }
are also be used with looping structures (while, do … while) or iteration structures (for, foreach). In these structures, {
and }
not only define the scope of the variables, they define the scope of the loop.
bool j = false;
while (j)
{
int i = 0;
}
// i doesn't exist here
// j does
Most now take it for granted that with looping structures, the { they see defines the start of the loop.
for ( i = 1; i ...
{
places[i].Z ...
}
Our lazy coding brains combined with our speed reading skills single out the first few characters on the line, and produce the above comprehended text.
Is i
in places[i]
in the same scope as the loop?
The actual code is thus:
int i = 0;
for ( i = 1; i < places.Count; i++ ) { problems++ }
{
places[i].Zip = "12345";
}
We can see the loop has very little to do with the scope of places[i]. This type of error would likely be very difficult to find. (Granted, in my overly simplistic example, it was easy to find. But when conditionals or parameters get long winded, and white space is added to break up long lines, and curly braces get pushed around, the confusion is an easy one to make, and a difficult one to read.)
Add to this confusion that some don’t even put curly braces around simple loops:
for ( int i = 1; i < places.Count; i++ )
places[i].Zip = "12345";
If we train our minds to look for { as both the start of scope and the start of looping structures, we must mentally decide each time we see one if it is indeed a behavioral modification or just a scope change.
If we instead train our minds to look for looping structure words (for, while, foreach, do … while) as the start of a loop and { at the beginning of a line as the start of scope not in a loop, the distinction in code is clear:
for ( int i = 1; i < places.Count; i++ ) {
places[i].Zip = "12345";
}
while ( j ) {
int i = places[k].Address;
}
int i = 0;
{
int j = places[k].City;
}
These 3 sets of code are much more legible with the curly braces after the looping structure verbiage than on a new line. The first two are looping structures, the third is a scope change.
This same methodology extends to higher level elements in C-style languages:
public void DoSomething( int ...
is much clearer than
public void DoSomething( int ...
{
Does the second example’s {
start a new scope inside the function? Probably not, but you don’t know this without reading to the end of the method declaration line.
This distinction is especially clear if the context around this code looks like so:
myevent.onclick += new EventHandler( {
// declare anonymous method
public void DoSomething( int a, string b, object c, int d, string e ) { return string.Format(“{0}{1}{2}{3}{4}{5}”, a, b, c, d, e; }
} );
I code specifically for readability and legibility. When curly braces are concerned I use these rules:
– special words like for, while, public, namespace, etc define the start of a specific type of behavior
– { on a line by itself starts a scope not associated with unique behavior
– Every looping structure contains { and } even when it is technically correct to omit them
These are far from the exhaustive list of rules I use for legibility. I also use rules like the following:
– Comment anything that looks unusual
– Use parenthesis and white space liberally
– Use incrementers ( i++, –j ) on their own line to specifically eliminate the confusion of “increment first then assign or assign then increment?”
– Use variable names that describe the context of its use, not of its variable type
– Add blank lines around specific blocks of functionality
– Make methods short and precise. If the method goes on for 3 pages with 4 or 5 nested scopes, it is time to refactor.
– Add spaces between variables, operators, parenthesis, and braces:
for( int i = 0; I < 10; i++ )
for(int i=0;i<10;i++)
Though these two are syntactically identical, the first is much more legible.
The good news is Visual Studio makes these types of decisions painless to implement across all your code or your entire team. In VS 2005, choose the Tools Menu -> Options -> Text Editor. You can modify the settings per language or globally for all languages. Adding spaces between variables, setting braces on the same line, and defining many other scenarios is simple as pie.
Did you just download a code sample that isn’t formatted the way you like? Open up each file you need to read in Visual Studio, remove the last } from the document and retype it. It will reformat the entire document to match the formatting preferences you’ve defined.
Now Visual Studio’s elegance starts to break down if you work in multiple formatting styles. Some organizations may require formatting that does not match your personal style. Visual Studio has no way to set curly brace styles per solution or per project. The closest you can come is saving each set of preferences, and loading each as you start up the project of choice – hardly an automated solution.