Coding Style: Curly Braces

Started by
72 comments, last by kunos 11 years ago

It seems to me that the main reason being put forward for preferring K&R (or similar) is saving space, but don't you think that this is a case of seriously getting things entirely the wrong way around? The purpose of a coding style is not to save space or to look pretty, it's to make code easier to read (because reading code is harder than writing code), to make wrong code look wrong and to make right code look right.

If we can all agree, or mostly agree, that a certain style is harder to read or fails in the other main criteria, then we should by definition also all agree (or mostly agree) that any other advantages that style may have are of reduced (or no) importance. If a given style takes 50% longer for a person to read and parse then that's time wasted for that person (and why obsess over saving a few blank lines if it comes at the cost of wasting someone's time?) If a given style makes right code look wrong (or worse - wrong code look right) then that style is obviously at best flawed, at worst completely broken.

Direct3D has need of instancing, but we do not. We have plenty of glVertexAttrib calls.

Advertisement

It seems to me that the main reason being put forward for preferring K&R (or similar) is saving space, but don't you think that this is a case of seriously getting things entirely the wrong way around? The purpose of a coding style is not to save space or to look pretty, it's to make code easier to read (because reading code is harder than writing code), to make wrong code look wrong and to make right code look right.

See my previous example.


	LSUINT32 LSE_CALL CTime::GetConstantStepUpdateTimesFromTicks( LSUINT64 _ui64Ticks, LSUINT32 &_ui32UnitsToNextUpdate ) {
		LSUINT64 ui64TimeNow = GetRealTime();
		LSUINT64 ui64Dif = ui64TimeNow - m_ui64LastRealTime;

		LSUINT32 ui32Count = static_cast<LSUINT32>(ui64Dif / _ui64Ticks);
		m_ui64LastRealTime += ui32Count * _ui64Ticks;

		// Determine how far this update lands between two other updates at the same fixed interval,
		//	in units of 1 1,000th.
		_ui32UnitsToNextUpdate = static_cast<LSUINT32>(((ui64Dif % _ui64Ticks) * 1000ULL) / _ui64Ticks);

		return ui32Count;
	}


If it were easier to read to put a blank line I would put one there. While keeping the brace on the same line as the function declaration.
It isn’t truly about saving space; that is just a simplification. It’s about deciding where blank lines go based on actual considerations for the code at hand rather than just following a “rule” (note that it is not meant to be such a rule but many make it out as such just as many over-simplify K&R as aiming to save space) which may or may not be appropriate for any given code block.


Again, strategically placed blank lines certainly do improve readability, but there is no rule or even a remote human consensus that blank (or lines containing only opening braces) improve readability in all cases after function headers, if’s, else’s, while’s, for’s, etc.

I personally believe that a blank line after a namespace declaration is universally easier to read.
So I put a blank line there. You could instead choose to put an opening brace on its own line there, but that is nothing but personal preference.


L. Spiro

I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid

On the other hand, you've got this:


if ((a || b) && (c || d) && (e || f)) {
    DoSomething ();
    DoSomethingElse ();
}

Versus this:


if ((a || b) && (c || d) && (e || f))
    DoSomething ();
    DoSomethingElse ();
}

The second one here is wrong (and won't even compile, but that's by the by for now) but the wrongness doesn't jump out at you like it should.

Direct3D has need of instancing, but we do not. We have plenty of glVertexAttrib calls.


if ((a || b) && (c || d) && (e || f))
    DoSomething ();
    DoSomethingElse ();
}

The second one here is wrong (and won't even compile, but that's by the by for now) but the wrongness doesn't jump out at you like it should.

It does jump on you immediately when the editor automatically indents the code.

    if ((a || b) && (c || d) && (e || f))
        DoSomething ();
    DoSomethingElse ();
}

On the other hand, you've got this:


if ((a || b) && (c || d) && (e || f)) {
    DoSomething ();
    DoSomethingElse ();
}

Versus this:


if ((a || b) && (c || d) && (e || f))
    DoSomething ();
    DoSomethingElse ();
}

The second one here is wrong (and won't even compile, but that's by the by for now) but the wrongness doesn't jump out at you like it should.

What would be even worse is if you have an open bracket somewhere before that and you are missing ITS' closing bracket. That errant closing bracket for that if statement would then take the place of the missing closing bracket for the previous one. Probably not terribly likely to happen, but if it did I bet it would be a pain to find.

On the other hand, you've got this:


if ((a || b) && (c || d) && (e || f)) {
    DoSomething ();
    DoSomethingElse ();
}

Versus this:

if ((a || b) && (c || d) && (e || f))
    DoSomething ();
    DoSomethingElse ();
}

The second one here is wrong (and won't even compile, but that's by the by for now) but the wrongness doesn't jump out at you like it should.


Basically, both sides can point out rare edge cases, which is why the debate never ends.

Every style has edge cases. You get around them by coding right.
For example, C++ makes it easy to leak memory. To “code right” I either added the new and then immediately add the delete when I was young, or use RAII as I grew more experienced.
Likewise, I never miss braces because both the opening and closing brace are added together, before the body of the block is added.
I can see fairly easily then if I missed something. Such a mistake is actually glaringly obvious, and similar edge cases exist in all styles.

It’s really not related to formatting any more than writing a delete for every new as a pair is. Safe coding practices prevent this type of issue 99.9% of the time (and I can personally say I have never fallen prey to the example you provided; the only time in any style I have ever gotten mismatched braces was during refactors of heavily nested code, and while they were nasty, they would have popped up regardless of the style I chose).


L. Spiro

I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid

On the other hand, you've got this:


if ((a || b) && (c || d) && (e || f)) {
    DoSomething ();
    DoSomethingElse ();
}

Versus this:


if ((a || b) && (c || d) && (e || f))
    DoSomething ();
    DoSomethingElse ();
}

The second one here is wrong (and won't even compile, but that's by the by for now) but the wrongness doesn't jump out at you like it should.

I've programmed in that style for a long time, it jumped out to me immediately, without any need for an editor to format it and before reading your last sentence pointing it out. I understand the point you are trying to make, but having coded like that for a long time, such mistakes very rarity occur, and when they do, i'm not digging through a ton of code to find it, it's generally pretty quick and easy to discover.

Check out https://www.facebook.com/LiquidGames for some great games made by me on the Playstation Mobile market.

It's obviously personal preference, but I very much prefer the first type (and leave away braces for single line statements... when I'm feeling evil that might include using a comma operator) because I find it much more readable and despise the javaesque second style.

Addendum: If speed doesn't matter, I'll much rather choose the python no-braces style (tabs only for indents!), though this practically enforces the second brace style for implicit line continuations due to parentheses, braces and brackets.

Both coding styles are fine and I would be fine using either. The only style I cannot stand is the GNU style of having half-indented braces. Very annoying to maintain, and if a real TAB slips through the code it's going to look real ugly with different tab settings.

Coding style is a programmer's signature. If you get to call the coding style to be used (or if it's your own personal project) pick a style you like and stick with it, consistency is more important here.

That being said, personally, I have a preference for putting my opening braces on their own line because it makes the blocks pop out more. I already put a lot of white lines in my code to separate the logical "sub-tasks" of a function, and a condition block of a few lines is definitely a sub-task that I would white-line anyway, so putting the brace on its own line feels more consistent and natural with my coding style.

It also serves to separate the condition from the blocks. For short conditions this is a non-issue, but for long conditions that span on multiple lines it becomes harder to quickly spot where the condition begins without that empty white line.


if ((a || b) && (c || d) && (e || f))
    DoSomething ();
    DoSomethingElse ();
}

The second one here is wrong (and won't even compile, but that's by the by for now) but the wrongness doesn't jump out at you like it should.

Then again, you can make the same example like this:


if ((a || b) && (c || d) && (e || f));
{
    DoSomething();
    DoSomethingElse();
}

And this will not even generate a compiler error, maybe a warning. Truth is I don't think a bracket style will prevent human errors in the code, as no matter where you place them, a single mistyped character can break them.

Personally I prefer to use indention over brackets to see the structure of a code, it's must faster to scan code by indention level then by looking for the tiny brackets. Also modern IDEs are more then capable of visualizing scopes for you, for example in QtCreator:

ideid.png

This topic is closed to new replies.

Advertisement