I'm reading some lecture notes of my C++ lecturer and he wrote the following:
Use Indentation // OK Never rely on operator precedence - Always use parentheses // OK Always use a { } block - even for a single line // not OK, why ??? Const object on left side of comparison // OK Use unsigned for variables that are >= 0 // nice trick Set Pointer to NULL after deletion - Double delete protection // not bad
The 3rd technique is not clear to me: what would I gain by placing one line in a { ... }
?
For example, take this weird code:
int j = 0;
for (int i = 0 ; i < 100 ; ++i)
{
if (i % 2 == 0)
{
j++;
}
}
and replace it with:
int j = 0;
for (int i = 0 ; i < 100 ; ++i)
if (i % 2 == 0)
j++;
What's the benefit of using the 1st version?
for (unsigned i = 100; i >= 0; --i)
.
(i % 2 == 0)
contradicts (2). You are relying on operator precedence, and the meaning is of course ((i % 2) == 0)
rather than (i % (2 == 0))
. I would classify rule 2 as "a valid sentiment but 'always' is wrong".
Let's attempt to also modify i
when we increment j
:
int j = 0;
for (int i = 0 ; i < 100 ; ++i)
if (i % 2 == 0)
j++;
i++;
Oh no! Coming from Python, this looks ok, but in fact it isn't, as it's equivalent to:
int j = 0;
for (int i = 0 ; i < 100 ; ++i)
if (i % 2 == 0)
j++;
i++;
Of course, this is a silly mistake, but one that even an experienced programmer could make.
Another very good reason is pointed out in ta.speot.is's answer.
A third one I can think of is nested if
's:
if (cond1)
if (cond2)
doSomething();
Now, assume you now want to doSomethingElse()
when cond1
is not met (new feature). So:
if (cond1)
if (cond2)
doSomething();
else
doSomethingElse();
which is obviously wrong, since the else
associates with the inner if
.
Edit: Since this is getting some attention, I'll clarify my view. The question I was answering is:
What's the benefit of using the 1st version?
Which I have described. There are some benefits. But, IMO, "always" rules don't always apply. So I don't wholly support
Always use a { } block - even for a single line // not OK, why ???
I'm not saying always use a {}
block. If it's a simple enough condition & behavior, don't. If you suspect someone might come in later & change your code to add functionality, do.
It's very easy to accidentally change control-flow with comments if you do not use {
and }
. For example:
if (condition)
do_something();
else
do_something_else();
must_always_do_this();
If you comment out do_something_else()
with a single line comment, you'll end up with this:
if (condition)
do_something();
else
//do_something_else();
must_always_do_this();
It compiles, but must_always_do_this()
isn't always called.
We had this issue in our code base, where someone had gone in to disable some functionality very quickly before release. Fortunately we caught it in code review.
must_always_do_this();
will execute if you comment //do_something_else();
if(debug) \n //print(info);
. Basically took out a whole library.
Fortunately we caught it in code review.
Ouch! That sounds so wrong. Fortunately we caught it in unit tests.
would be much better!
I have my doubts as to the competence of the lecturer. Considering his points:
OK Would anyone really write (or want to read) (b*b) - ((4*a)*c)? Some precedences are obvious (or should be), and the extra parentheses just add to confusion. (On the other hand, you _should_ use the parentheses in less obvious cases, even if you know that they're not needed.) Sort of. There are two wide spread conventions for formatting conditionals and loops: if ( cond ) { code; } and: if ( cond ) { code; } In the first, I'd agree with him. The opening { is not that visible, so it's best to assume it's always there. In the second, however, I (and most of the people I've worked with) have no problem with omitting the braces for a single statement. (Provided, of course, that the indentation is systematic and that you use this style consistently. (And a lot of very good programmers, writing very readable code, omit the braces even when formatting the first way.) NO. Things like if ( NULL == ptr ) are ugly enough to hinder readability. Write the comparisons intuitively. (Which in many cases results in the constant on the right.) His 4 is bad advice; anything which makes the code unnatural makes it less readable. NO. Anything but int is reserved for special cases. To experienced C and C++ programmers, the use of unsigned signals bit operators. C++ doesn't have a real cardinal type (or any other effective subrange type); unsigned doesn't work for numeric values, because of the promotion rules. Numerical values on which no arithmetic operations would make sense, like serial numbers, could presumably be unsigned. I'd argue against it, however, because it sends the wrong message: bitwise operations don't make sense either. The basic rule is that integral types are int, _unless_ there is a significant reason for using another type. NO. Doing this systematically is misleading, and doesn't actually protect against anything. In strict OO code, delete this; is often the most frequent case (and you can't set this to NULL), and otherwise, most delete are in destructors, so you can't access the pointer later anyway. And setting it to NULL doesn't do anything about any other pointers floating around. Setting the pointer systematically to NULL gives a false sense of security, and doesn't really buy you anything.
Look at the code in any of the typical references. Stroustrup violates every rule you've given except for the first, for example.
I'd suggest that you find another lecturer. One who actually knows what he's talking about.
delete this
, is it more common than I have seen? I don't tend to think setting a pointer to NULL after use is that bad of a thing to do but YMMV. Maybe it's just me but most of his guidelines don't seem that bad.
if (ptr = NULL)
unless you write it as if ((ptr = NULL))
. Have to agree with James Kanze that the ugliness of having NULL
first makes it a definite NO for me.
unsigned
indicates an aspiration on the part of the programmer that the variable should represent only positive numbers. Mixing with signed numbers will usually cause a compiler warning which was probably what the lecturer was intending.
size_t
, anyone?
All the other answers defend your lecturer’s rule 3.
Let me say that I agree with you: the rule is redundant and I wouldn’t advise it. It’s true that it theoretically prevents errors if you always add curly brackets. On the other hand, I’ve never encountered this problem in real life: contrary to what other answers imply, I’ve not once forgotten to add the curly brackets once they became necessary. If you use proper indentation, it becomes immediately obvious that you need to add curly brackets once more than one statement is indented.
The answer by Component 10 actually highlights the only conceivable case where this could really lead to an error. But on the other hand, replacing code via regular expression always warrants enormous care anyway.
Now let’s look at the other side of the medal: is there a disadvantage to always using curly brackets? The other answers simply ignore this point. But there is a disadvantage: it takes up a lot of vertical screen space, and this in turn can make your code unreadable because it means you have to scroll more than necessary.
Consider a function with a lot of guard clauses at the beginning (and yes, the following is bad C++ code but in other languages this would be quite a common situation):
void some_method(obj* a, obj* b)
{
if (a == nullptr)
{
throw null_ptr_error("a");
}
if (b == nullptr)
{
throw null_ptr_error("b");
}
if (a == b)
{
throw logic_error("Cannot do method on identical objects");
}
if (not a->precondition_met())
{
throw logic_error("Precondition for a not met");
}
a->do_something_with(b);
}
This is horrible code, and I argue strongly that the following is vastly more readable:
void some_method(obj* a, obj* b)
{
if (a == nullptr)
throw null_ptr_error("a");
if (b == nullptr)
throw null_ptr_error("b");
if (a == b)
throw logic_error("Cannot do method on identical objects");
if (not a->precondition_met())
throw logic_error("Precondition for a not met");
a->do_something_with(b);
}
Similarly, short nested loops benefit from omitting the curly brackets:
matrix operator +(matrix const& a, matrix const& b) {
matrix c(a.w(), a.h());
for (auto i = 0; i < a.w(); ++i)
for (auto j = 0; j < a.h(); ++j)
c(i, j) = a(i, j) + b(i, j);
return c;
}
Compare with:
matrix operator +(matrix const& a, matrix const& b) {
matrix c(a.w(), a.h());
for (auto i = 0; i < a.w(); ++i)
{
for (auto j = 0; j < a.h(); ++j)
{
c(i, j) = a(i, j) + b(i, j);
}
}
return c;
}
The first code is concise; the second code is bloated.
And yes, this can be mitigated to some extent by putting the opening brace on the previous line. So: if you insist on curly braces, at least put the opening brace on the previous line.
In short: don’t write unnecessary code which takes up screen space.
In the time since originally writing the answer I’ve mostly accepted the prevailing code style and use braces unless I can put the entire single statement on the previous line. I still maintain that not using redundant braces is usually more readable, and I have still never encountered a bug caused by this.
if (a == nullptr) { throw null_ptr_error("a"); }
as one line.
The codebase I'm working on is scattered with code by people with a pathological aversion to braces, and for the people who come along later, it really can make a difference to maintainability.
The most frequent problematic example I have encountered is this:
if (really incredibly stupidly massively long statement that exceeds the width of the editor) do_foo;
this_looks_like_a_then-statement_but_isn't;
So when I come along and wish to add a then-statement, I can easily end up with this if I'm not careful:
if (really incredibly stupidly massively long statement that exceeds the width of the editor) do_foo;
{
this_looks_like_a_then-statement_but_isn't;
i_want_this_to_be_a_then-statement_but_it's_not;
}
Given that it takes ~1 second to add braces and can save you at minimum a few confused minutes debugging, why would you ever not go with the reduced-ambiguity option? It seems like false economy to me.
if(really long...editor){ do_foo;}
help you avoid this case? Seems like the problem would still be the same. Personally I prefer to avoid braces when not necessary, however that has nothing to do with the time needed to write them but the reduced readability due to the two extra lines in the code.
My 2c:
Use Indentation
Obviously
Never rely on operator precedence - Always use parentheses
I wouldn't use words "never and "always", but in general I see this rule being useful. In some languages (Lisp, Smalltalk) this is a non-issue.
Always use a { } block - even for a single line
I never do that and never had a single problem, but I can see how it can be good for students, esp. if they studied Python before.
Const object on left side of comparison
Yoda conditions? No, please. It hurts readability. Just use the maximum warning level when you compile your code.
Use unsigned for variables that are >= 0
OK. Funny enough, I've heard Stroustrup disagree.
Set Pointer to NULL after deletion - Double delete protection
Bad advice! Never have a pointer which points to a deleted or non-existing object.
unsigned
is broken", one of the problems is that when C++ compares similar sized signed and unsigned types, it converts to the unsigned one before doing the comparison. Which results in a change in value. Converting to the signed wouldn't necessarily be much better; the comparison should really take place "as if" both values were converted to a larger type which could represent all of the values in either type.
unsigned
. I'm sure he has no problem with exp(double)
returning a value more than MAX_INT
:-). But once again, the real problem is implicit conversions. int i = exp( 1e6 );
is perfectly valid C++. Stroustrup actually proposed deprecating lossy implicit conversions at one point, but the committee wasn't interested. (An interesting question: would unsigned
-> int
be considered lossy. I'd consider both unsigned
-> int
and int
-> unsigned
lossy. Which would go a long way to making unsigned
OK
It is more intuitive and easily understandable. It makes the intent clear.
And it ensures that the code doesn't break when a new user might unknowingly miss the {
, }
while adding a new code statement.
Makes the intent clear
+1, this is probably the most concise and accurate reason.
To add to the very sensible suggestions in previous answers, one example I encountered while refactoring some code of where this becomes critical was as follows: I was altering a very large codebase to switch from one API to another. The first API had a call to set Company Id as follows:
setCompIds( const std::string& compId, const std::string& compSubId );
whereas the replacement needed two calls:
setCompId( const std::string& compId );
setCompSubId( const std::string& compSubId );
I set about changing this using regular expressions which was very successful. We also passed the code through astyle, which really made it very much more readable. Then, part way through the review process, I discovered that in some conditional circumstances it was changing this:
if ( condition )
setCompIds( compId, compSubId );
To this:
if ( condition )
setCompId( compId );
setCompSubId( compSubId );
which is clearly not what what was required. I had to go back to the beginning do this again by treating the replacement as completely within a block and then manually altering anything that ended up looking goofy (at least it wouldn't be incorrect).
I notice that astyle now has the option --add-brackets
which allows you to add brackets where there are none and I strongly recommend this if you ever find yourself in the same position as I was.
#define FOO() func1(); \ func2();
(with a linebreak after the backslash), same goes for search and replace. That said, I have seen "always use braces" advanced as a style rule precisely because it saves you from wrapping all your multi-statement macros in do .. while(0)
. But I disagree.
inline
), then you should probably aim for them to work as much like a function as possible, using the do { ... } while(0)
trick if necessary (and lots of extra parentheses. But that still wouldn't stop you from using braces everywhere, if that's the house style. (FWIW: I've worked in places with varying house styles, covering all of the styles discussed here. I've never found any to be a serious problem.)
I am using {}
everywhere except a few cases where it's obvious. Single line is one of the cases:
if(condition) return; // OK
if(condition) //
return; // and this is not a one-liner
It may hurt you when you add some method before return. Indentation indicates that return is executing when condition is met, but it will return always.
Other example in C# with using statment
using (D d = new D()) // OK
using (C c = new C(d))
{
c.UseLimitedResource();
}
which is equivalent to
using (D d = new D())
{
using (C c = new C(d))
{
c.UseLimitedResource();
}
}
using
statement and you don't have to :)
using
).
The most pertinent example I can think of:
if(someCondition)
if(someOtherCondition)
DoSomething();
else
DoSomethingElse();
Which if
will the else
be paired with? Indentation implies that the outer if
gets the else
, but that's not actually how the compiler will see it; the inner if
will get the else
, and the outer if
doesn't. You would have to know that (or see it behave that way in debugging mode) to figure out by inspection why this code might be failing your expectations. It gets more confusing if you know Python; in that case you know that indentation defines code blocks, so you would expect it to evaluate according to the indentation. C#, however, doesn't give a flying flip about whitespace.
Now, that said, I don't particularly agree with this "always use brackets" rule on its face. It makes code very vertically noisy, reducing the ability to read through it quickly. If the statement is:
if(someCondition)
DoSomething();
... then it should be written just like this. The statement "always use brackets" sounds like "always surround mathematical operations with parentheses". That would turn the very simple statement a * b + c / d
into ((a * b) + (c / d))
, introducing the possibility of missing a close-paren (the bane of many a coder), and for what? The order of operations is well-known and well-enforced, so the parentheses are redundant. You'd only use parentheses to enforce a different order of operations than would normally be applied: a * (b+c) / d
for instance. Block braces are similar; use them to define what you want to do in cases where it differs from the default, and is not "obvious" (subjective, but usually pretty common-sense).
else
with the first if
instead of the second. Please remove the downvote.
Because when you have two statements without {}
, it's easy to miss an issue. Let's assume that the code looks like this.
int error = 0;
enum hash_type hash = SHA256;
struct hash_value *hash_result = hash_allocate();
if ((err = prepare_hash(hash, &hash_result))) != 0)
goto fail;
if ((err = hash_update(&hash_result, &client_random)) != 0)
goto fail;
if ((err = hash_update(&hash_result, &server_random)) != 0)
goto fail;
if ((err = hash_update(&hash_result, &exchange_params)) != 0)
goto fail;
goto fail;
if ((err = hash_finish(hash)) != 0)
goto fail;
error = do_important_stuff_with(hash);
fail:
hash_free(hash);
return error;
It looks fine. The issue with it is really easy to miss, especially when the function containing the code is way larger. The issue is that goto fail
is ran unconditionally. You can easily imagine how frustrating this is (making you ask why last hash_update
always fails, after all everything looks fine in hash_update
function).
However, that doesn't mean I'm for adding {}
everywhere (in my opinion, seeing {}
everywhere is annoying). While it can cause issues, it never did for my own projects, as my personal coding style forbids conditionals without {}
when they aren't on the same line (yes, I agree that my coding style is unconventional, but I like it, and I use project's code style when contributing to other projects). This makes the following code fine.
if (something) goto fail;
But not the following one.
if (something)
goto fail;
It makes your code more readable by clearly defining the scope of your loops and conditional blocks. It also saves you from accidental mistakes.
wrt 6: It's safer because deleteing a null pointer is a no-op. So if you happen to accidentally go through that path twice, you won't cause memory corruption be freeing memory that is either free or has been allocated to something else.
This is most of an issue with static file scope objects and singletons that have not very clear lifetimes and have been known to get recreated after they've been destroyed.
In most cases, you can avoid the need for this by using auto_ptrs
NULL
after deleting it. If NULL
is a correct value for the pointer to have in those circumstances; e.g. the pointer points to a cached value, and NULL
indicates an invalid cache. But when you see someone setting a pointer to NULL
as the last line in a destructor, you wonder if he knows C++.)
I like Luchian's accepted answer. In fact, I learned the hard way that he is right, so I do always use braces, even for single-line blocks. However, personally I make an exception when writing a filter, as you are in your example. This:
int j = 0;
for (int i = 0 ; i < 100 ; ++i)
{
if (i % 2 == 0)
{
j++;
}
}
looks cluttered to me. It separates the 'for' loop and the 'if' statement into separate actions, when really your intent is a single action: to count all of the integers divisible by 2. In a more expressive language, this could be written something like:
j = [1..100].filter(_%2 == 0).Count
In languages which lack closures, the filter cannot be expressed in a single statement, but must be a for loop followed by an if statement. However, it is still one action in the mind of the programmer, and I believe that should be reflected in the code, like so:
int j = 0;
for (int i = 0 ; i < 100 ; ++i)
if (i % 2 == 0)
{
j++;
}
for (int i = 0; i < 100; i += 2);
, for the sake of continuing the argument about indentation ;-) There's probably a whole separate bunfight we could have, how "best" to express the logic "for each i
in a certain range with a certain property" in C++ without a loop, using some nightmare combination of standard algorithms, filter_iterator
and/or counting_iterator
.
i
in a certain range with a certain property". It's just that usually on SO, people are very quick to ignore the actual question in favour of a completely different approach to the example given. But indenting is important, so we don't ;-)
One option for helping to prevent the errors that have been described in previous answers is to inline what you want to happen when you don't use braces. It makes it much harder to not notice the errors when you try to modify the code.
if (condition) doSomething();
else doSomethingElse();
if (condition) doSomething();
doSomething2(); // Looks pretty obviously wrong
else // doSomethingElse(); also looks pretty obviously wrong
else
is not associated with an if
.
Looking through the answers no one's explicitly stated the sort of practice I make a habit of, telling the story of your code:
int j = 0;
for (int i = 0 ; i < 100 ; ++i)
{
if (i % 2 == 0)
{
j++;
}
}
Becomes:
int j = 0;
for (int i = 0 ; i < 100 ; ++i)
{
if (i % 2 == 0) j++;
}
Putting the j++
on the same line as the if should signal to anyone else, "I only want this block to ever increment j
". Of course, this is only worthwhile if the line is as simplistic as possible, because putting a breakpoint here, as peri mentions, is not going to be very useful.
In fact, I've just run across part of the Twitter Storm API that has this 'sort' of code in Java. Here is the relevant snippet from the executed code, on page 43 of this slideshow:
...
Integer Count = counts.get(word);
if (Count=null) count=0;
count++
...
The for loop block has two things in it, so I wouldn't inline that code. I.e., never:
int j = 0;
for (int i = 0 ; i < 100 ; ++i) if (i % 2 == 0) j++;
It's awful and I don't even know if it works (as intended); don't do this. New lines and braces help distinguish separate, but related pieces of code, in the same way a comma or a semicolon do in prose. The above block is as bad a really long sentence with a few clauses and some other statements that never break or pause to distinguish separate parts.
If you really want to telegraph to someone else it's a one-line only job, use a ternary operator or ?:
form:
for (int i = 0 ; i < 100 ; ++i) (i%2 ? 0 : >0) j++;
But this is verging on code golf, and I think it is not great practice (it's not clear to me if I should put the j++ on one side of the :
or not). NB I've not run a ternary operator in C++ before, and I don't know if this works, but it does exist.
In short:
Imagine how your reader (i.e., the person maintaining the code) interprets your story (code). Make it as clear for them as possible. If you know the novice coder/student is maintaining this, perhaps even leave in as many {}
as possible, just so they don't get confused.
for
loop on a single line, why shouldn’t this work? It works for the same reason that you can omit the braces; newline is simply not significant in C++. (3) Your conditional operator example, besides being horrible, is invalid C++.
If you are a compiler, it doesn't make any difference. Both are the same.
But for programmers, the first one is more clear, easy to read and less error-prone.
{
on it's own line, anyway.
Another example of adding curly braces.
Once I was searching for a bug and found such code:
void SomeSimpleEventHandler()
{
SomeStatementAtTheBeginningNumber1;
if (conditionX) SomeRegularStatement;
SomeStatementAtTheBeginningNumber2;
SomeStatementAtTheBeginningNumber3;
if (!SomeConditionIsMet()) return;
OtherwiseSomeAdditionalStatement1;
OtherwiseSomeAdditionalStatement2;
OtherwiseSomeAdditionalStatement3;
}
If you read the method line-by-line you will notice that there is a condition in the method that returns if it's not true. But actually it looks like 100 other simple event handlers that set some variables based on some conditions. And one day the Fast Coder comes in and adds additional variable setting statements at the end of the method:
{
...
OtherwiseSomeAdditionalStatement3;
SetAnotherVariableUnconditionally;
}
As a result, the SetAnotherVariableUnconditionnally is executed when the SomeConditionIsMet(), but the fast guy didn't notice it because all lines are almost similar in size and even when the return condition is vertically indented it is not-so noticeable.
If the conditional return is formatted like this:
if (!SomeConditionIsMet())
{
return;
}
it is much noticeable and the Fast Coder will find it at a glance.
return
statement within the body of a function before adding something to it, you shouldn't let the fast coder get near your code. You won't stop such a guy from trolling around your code by including braces.
I consider the first one to be clearer than the second. It gives the feeling of closing instructions. With short code it is fine, but when code gets complex, {...}
helps a lot, even if it is endif
or begin...end
.
// First
int j = 0;
for (int i = 0 ; i < 100 ; ++i)
{
if (i % 2 == 0)
{
j++;
}
}
// Second
int j = 0;
for (int i = 0 ; i < 100 ; ++i)
if (i % 2 == 0)
j++;
i++;
It is best to set the pointer to NULL when you have finished with it.
Here is an example why:
Class A does the following:
Allocates a block of memory Then some time later, it delete this block of memory but does not set the pointer to NULL
Class B does the following
Allocates memory (and in this instance it happens to be given the same memory block that was deleted by class A.)
At this point both Class A and Class B have pointers pointing to the same memory block, as far as Class A is concerned this block of memory does not exists because it is finished with it.
Consider the following problem:
What if there was a logic error in Class A which resulted in it writing to memory that now belongs to Class B?
In this particular instance, you will not get an bad access exception error because the memory address is legal, all the while class A is now effectively corrupting class B data.
Class B may eventually crash if it encounters unexpected values and when it does crash, chances are, you will spend quite a long time hunting this bug in class B when the problem is in class A.
If you had set the deleted memory pointer to NULL, you would have gotten an exception error as soon as any logic errors in Class A tried to write to NULL pointer.
If you are worried about the logic error with double delete when pointers are NULL for the second time, then add assert for this.
Also: If you are going to down vote, please explain.
There are a number of possible ways of writing control statements; certain combinations of them may co-exist without impairing legibility, but other combinations will cause trouble. The style
if (condition)
statement;
will co-exist comfortably with some of the other ways of writing control statements, but not so well with others. If multi-line controlled statements are written as:
if (condition)
{
statement;
statement;
}
then it will be visually obvious which if
statements control a single line and which ones control multiple lines. If, however, multi-line if
statements are written as:
if (condition) {
statement;
statement;
}
then the likelihood of someone trying to extend a single-statement if
constructs without adding the necessary braces may be much higher.
The single-statement-on-next line if
statement may also be problematic if the codebase makes significant use of the form
if (condition) statement;
My own preference is that having the statement on its own line generally enhances legibility except in cases where there are many if
statements with similar control blocks, e.g.
if (x1 > xmax) x1 = xmax;
if (x1 < xmin) x1 = xmin;
if (x2 > xmax) x2 = xmax;
if (x2 < xmin) x2 = xmin;
etc.
in which case I will generally precede and follow such groups of if
statements with a blank line to visually separate them from other code. Having a range of statements that all start with if
at the same indentation will then provide a clear visual indication that there's something unusual.
After 10 years of being in camp "always use braces" I recently switched to not using them as much anymore. Mostly inspired by some of Uncle Bob's arguments around how to write clean code I now believe that it is more readable to write them without the braces.
if(guardClause)
throw new SomeException(..)
Uncle Bob argues that writing more than one line of code inside an if/for statement is a potential readability smell.
e.g.
if(someCondition)
{
doTechnicalThingX();
doTechnicalThingY();
doTechnicalThingZ();
}
Should probably be refactored as
if(someCondition)
doFunctionalThingA();
Somehow for me it helps not putting the braces there because I get the reminder that I'm writing too much code inside the if block.
I do believe that code style is a team decision as others have mentioned.
I have to admit that I do not always use {}
for single lines, but it's a good practise.
Let’s say you write code without brackets that looks like this: for (int i = 0; i < 100; ++i) for (int j = 0; j < 100; ++j) DoSingleStuff();
And after some time you want to add some other stuff in the j
loop, and you just do that by alignment and forget to add brackets.
Memory deallocation is faster. Let’s say you have a big scope and create big arrays inside (without new so they are on the stack). Those arrays are removed from memory just after you leave the scope. But it is possible that you use that array in one place and it will be on the stack for a while and be some kind of rubbish. As a stack have limited and quite small size, it is possible to exceed the stack size. So in some cases it is better to write {} to preventing that. Note that this is not for a single line, but for such situations: if (...) { //SomeStuff... {//we have no if, while, etc. //SomeOtherStuff } //SomeMoreStuff }
The third way to use is similar to the second. It is just not to make the stack cleaner, but to open some functions. If you use mutex in long functions usually it is better to lock and unlock just before accessing data and just after finishing reading/writing that. Note: This way is used if you have some of your own class or struct with a constructor and destructor to lock memory.
What is more: if (...) if (...) SomeStuff(); else SomeOtherStuff(); // Goes to the second if, but alignment shows it is on first...
All in all, I cannot say, what the best way to always use {}
is for a single line, but it is nothing bad to do that.
If you write compiling code brackets for a single line does nothing, but if your code will be interpreted it slows the code very very slightly. Very slightly.
Always having curly braces is a very simple and robust rule. However, the code may look inelegant when there are a lot of braces.
If the rules allow to omit curly braces then there should be more detailed style rules and more sophisticated tools. Otherwise it may easily result in chaotic and confusing (not elegant) code.
Therefore looking at a single style rule separate from the rest of the style guides and tools used is likely fruitless. I will just bring some important details about that rule #3 that haven't even been mentioned in other answers.
The first interesting detail is that most proponents of that rule agree to violate it in the case of else
. In other words, they do not want it to result with such code:
// Pedantic rule #3
if ( command == Eat )
{
eat();
}
else
{
if ( command == Sleep )
{
sleep();
}
else
{
if ( command == Drink )
{
drink();
}
else
{
complain_about_unknown_command();
}
}
}
Instead, if they see it they may even suggest to write it like this:
// Not fully conforming to rule #3
if ( command == Eat )
{
eat();
}
else if ( command == Sleep )
{
sleep();
}
else if ( command == Drink )
{
drink();
}
else
{
complain_about_unknown_command();
}
That is technically a violation of rule #3 since there are no curly brackets between else
and if
but majority consider it more obvious and easy to read. Such duality of the rule surfaces when trying to apply it to a code base automatically with a mindless tool. Indeed, why argue? Just let a tool to apply the style automatically.
The second detail (that is also often forgotten by proponents of that rule) is that the illusion errors that may happen are never only because of violations of that rule #3. Actually, those almost always involve violations of rule #1 too (that no one argues with). Again from the viewpoint of automatic tools, it is not hard to make a tool that immediately complains (or even fixes) when rule #1 is violated and so most of the errors can be caught timely.
The third detail (that is often forgotten by opponents of that rule) is the confusing nature of an empty statement that is represented by a single semicolon. Most developers with some experience became confused sooner or later by a sole misplaced semicolon or by an empty statement that is written using a sole semicolon. Two curly braces instead of a single semicolon are visually way easier to spot.
So TL;DR my suggestion is instead of agreeing such rules agree on configuration of auto-formatting tools and make these a part of build process. The tools are often smarter than participants of such argument.
Success story sharing
i++
beforej++
, then both variables will still be in scope when they're used.i++;
in a way that shows immediately that it is not part of the loop. (In the past, this might have been a reasonable argument, and I've seen such problems. About 20 years ago. Not since.)