Cleaner code

Pages: 12
The reason for me to write this article is the fact that many people don't seem to know (or care) about code readability. Readability is the base for portability, re-usability and understandability (!).
Without proper code you cannot ask help on these forums without getting complaints, so read carefully; these are some tips and tricks to clean up your code.

This is a guideline, I do not say this is perfect. I just place a good way to do it, it's up to you to decide if you use it or not.

This guide is not considered complete but should help you well on your way, all suggestions are welcome.

On Brackets
Always put brackets on a empty line and put opening and closing brackets on the same "height" in your code. Anything that goes in between the two brackets should be tabbed to the right by a number which is consistent over all your code. (I use 4 spaces in my example) This style of bracketing is called, Allman style.
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>

using std::cout;
using std::endl;

int main()
{
    for(int i = 0; i < 9; i++)
    {
        cout << i << endl;
    }
    return 0;
}

There are, of course, other ways to do this. One is a slight variation of the Allman style: Whitesmith style. The brackets are put on the same level as the inner statements.
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>

using std::cout;
using std::endl;

int main()
    {
    for(int i = 0; i < 9; i++)
        {
        cout << i << endl;
        }
    return 0;
    }

When it is not important to see the text clearly, but rather see how different statements relate to one another (mainly if/else relationships), you can also use 1TBS (The One True Brace Style):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>

using std::cout;
using std::endl;

int main()
{
    for(int i = 0; i < 9; i++)
    {
        // Allman, up to now, time to go 1TBS for If/Else
        if (i < 5) {
            cout << i << endl;
        } else {
            cout << i*2 << "\t";
        } // And of if/else clause, the last bracket is the only one that takes up it's own line
        // Allman again
    }
    return 0;
}


On Comments
Commenting is done to improve readability, but it is also possible to make your comments more readable. Use multi-line comments only when needed and avoid putting comments at the end of code lines. Avoid tabbing your comments, use newlines to make things clearer. See On Consistency for more information.

The following comments may seem worthless, but I'm just trying to make clear what I told above.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>

using std::cout;
using std::endl;

int main()
{
    // Count
    for(int i = 0; i < 9; i++)
    {
        cout << i << endl;
    }

    // Program termination
    return 0;
}


On Consistency (General)
When different alternatives achieve the same result (at the same speed and both in the same amount of code lines), assure that you remain consistent to a single method. This applies to post- and prefix additions and subtractions (++ / --), as well as functional and C-style conversions int() and (int).
Whatever you do, be consistent.

On Function Calls (and definitions)
Spaces are all we will talk about on this subject. Be consistent with them. Generally, don't put spaces before or after parenthesis. Use them only after a comma (and only put a single one, in that case).
power(3, 5)

On Initialization
Consistency applies to initializations, too:
When given the choice between initializing at the start or later, use a single method. If you, however are left without a choice on which to use, use which ever you need. Furthermore, use proper spacing when creating pointers or references (or references to pointers to pointers to pointers to references to blablabla).
Any of the following are fine, but just use ONE style for all of your code.
1
2
3
4
int**& Variable;
int **& Variable;
int **&Variable;
int** &Variable;


On Naming
The following is a guideline and is open for change (as long as it's consistent, of course).

Naming is important for functions, classes, structures, unions, variables, namespaces and so on.
How to do good naming?
1. Make sure you name things by what they do (or are).
2. Possibly prefix them by a one or two lowercase character that describes the named instance. (c for classes, s for strings, i for integers, d for doubles, etc)
3. Start every word with a uppercase character and use lowercases for the rest. (An integer could become: iNumber)

A single exception to these rules are loop-variables. These are often named by a single lowercase character.

On Operators
Operators that are used for comparison and assignment should always be post and prefixed by a single space, other (arithmetic) operators have no generally accepted spacing usage. If you, however get very complicated statements by the lack of spaces, use them where you want them. (Two exceptions of this rule are << and >>, but ONLY when they are used for in- and output streams)
1
2
int iNumber = 6+5;
int iReturnValue = 4*iNumber +3;


On Preprocessor Directives
All spacing and newline rules apply here. For #define, however, make sure you make them differentiable from normal variables (making their names entirely uppercase is one method to do so, pre- AND postfixing their names with _ is another. You are free to do whatever you want, just keep things clear.)
Last edited on
I actually disagree with everything you recommend, except for consistency. Most of these directly violate
Rule #0 in C++ Coding Standards: Don't sweat the small stuff (or know what not to standardize),
but some I disagree with for other reasons as well.

Your "On Brackets" section is in direct violation of Rule #0;

Your "On Comments" section is just outright wrong. The length of a comment should be the length
needed to describe what needed to be described in the first place. Arbitrarily suggesting one line
comments leads to useless comments, such as the two you provided in the example; any C++
programmer knows that "return 0;" from a function named "main" terminates the program, no comment
saying so is necessary.

Your "On Function Calls" section is in violation of Rule #0;

I disagree with your "On Initialization" section in that in C++ it is best practice to always initialize
at the point of instantiation, and only not do that when it is impossible (which is rare).

Your "On Naming" section is sort of addressed by Rule #0, but my main beef with it is point #2.
I, as do many other C++ programmers, find Hungarian notation to be less readable. Point #3 is
not good as a blanket statement.

Your "On Operators" section is in violation of Rule #0;

Your recommendation of bracketing macros with underscores in "On Preprocessor Directives" is in
violation of the C++ standard itself, which says that all identifies beginning with a leading underscore
are reserved.

(And by the way, all of your for() loop examples are syntactically incorrect.)


....
Last edited on
I strongly disagree. It's important that other people can read and understand it too.
Jsmith, I edited a bit of the main post and I can't tell you enough that this is just my view. I'm not trying to standardize my vision, I'm just trying to make clear how important several attributes are and how they can contribute to better readabiliity.

One thing I agree with you about is On Initialization, which I will now change.

The only two real statements that are up when you consider the previously mentioned are about Naming and Commenting.

I added the note to my commenting part that reads: The following comments may seem worthless, but I'm just trying to make clear what I told above.

Now, on naming. As said, point 2 is POSSIBLE, but not a necessity. It's an expansion on point 1 but is still optional. Point 3 is just for general readability (and in the example I gave after that part I combined point 2 and 3).
Under 'On Brackets' you should show more indentation styles, Allman is good but not the only one
Added 1TBS and Whitesmith too. ;)
@Kyon: I understand that it is only your view. Your "thesis" was to provide suggestions for improving the readability
of one's code. I don't really think any of your suggestions do that. First of all, readability is subjective. Some people
like putting the opening brace on the same line as the if() and some people abhor it. Some people like putting the
opening brace on the next line and some people abhor that. From an objective standpoint, neither is any better. It's
what the programmer is used to that counts. For that reason, I believe that when editing source files, you should
maintain the same style of braces within the file. Every file needn't be the same, but at least within a file it is
consistent (consider how confusing it would be reading a source file that used half Whitesmith and half Allman). The
reason I say every file needn't be the same is because in doing so, you force half the programmers in an organization
to use a brace style they abhor (ie, find less readable).

On comments:
Use multi-line comments only when needed and avoid putting comments at the end of code
lines
. This sounds like one-liners are best. I disagree. If you want to talk about comments, you should say
something about "Comments should describe why the code does what it is doing, not what the code is
doing. If it is necessary to describe the what, then the code itself should be made more readable." Also, I would
not bother providing a bad example of what you are suggesting. Either provide a good one or none at all.

On Naming: (2) and (3) are again subjective; one is neither better nor worse than the other. I personally do not
use any form of prefixing; I find that my code is more readable to me if I use complete, spelled out words
(examples: firstName, lastName instead of fName, lName). Others will swear to Hungarian notation. Others will
swear that prefixing members with m_ makes their code more readable. I find it does not help me. I could even
argue that any form of Hungarian notation is contrary to generic programming. For example, in a template class, I
might not know the type of a variable. It might be int, it might be float, it could be std::string. How to prefix that
in a meaningful way? And I'm not sure what prefixing variable names does for me anyway. Is it not obvious from
the usage of "foo" that it is a class or struct? Why should I care if "foo" is a struct vs. a class or vice versa?

Your section on preprocessor directives is still in violation of the C++ standard regarding reservation of all identifiers
beginning with leading underscores.

The bottom line is that mandating a particular formatting style does not improve readability in general. Everyone
has their own preferences. The only formatting rule that I can think of that applies across the board to improve
readability is to be consistent.

closed account (EzwRko23)
My own set of rules of writing readable programs (applies not only to C++):
1. Don't repeat yourself.
2. Keep methods and functions short. Less than 10 lines is perfect, more than 20 lines is suspicious, more than 40 is a serious problem.
3. Make each method responsible for just one thing and make it do it good.
4. Make each class represent a single concern / entity / aspect.
5. Do not put any comments in code explaining what the code does. It should be self-explanatory.
6. Document interfaces in great detail.
7. Document purpose of things.
8. First make it simple, elegant and bugfree **then** optimize some bottlenecks if needed.
9. Never allow circular dependencies between objects / classes / modules / methods.
10. Think twice before using implementation inheritance. Don't override methods with implementation.
11. Don't generalize until you have at least two special cases implemented and working.
12. Use language that provides enough abstraction power and does not force you to use 7 lines to do trivial things like printing a sequence of numbers.

English:
 
Print consecutive integers from 1 until 9, each in separate line.


Scala:
 
1 until 9 foreach println



C++: (LOL)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>

using std::cout;
using std::endl;

int main()
{
    // Count
    for(int i = 0; i < 9; i++)
    {
        cout << i << endl;
    }

    // Program termination
    return 0;
}



Last edited on
xorebxebx wrote:
5. Do not put any comments in code explaining what the code does. It should be self-explanatory.
xorebxebx then wrote:
1
2
3
    // Count
...
    // Program termination 
xorebxebx probably wrote:
How do i double standard?
Last edited on
closed account (EzwRko23)
If you read the thread from the beginning you would note this code is not mine. I just copied it from the first post. You are right, these are examples of useless comments, which violate my point 5.
Last edited on
Oh, sorry; my mistake.
xorebxebx wrote:
Scala:
1 until 9 foreach println

Doesn't this just prints 9 new line characters?
I don't know Scala but I think equivalent pseudo-code would be:
1
2
foreach i in [1 .. 9]
        print(i + "\n")

Just to clarify; the "1 until 9 foreach" would become "foreach i in [1 .. 9]" and the "println" would become "print(i + "\n")"
I'm guessing Scala has a temporary variable, like Perl's $_, and when you use a value without assigning it to a variable it probably gets stored in the temporary variable. If you then call println without a value it uses the temporary variable; so in pseudo-assembly,
1 until 9 foreach println
becomes (assume dest, src syntax)
1
2
3
4
5
6
7
8
TMPVAR = 1
.reloop:
push (stack), TMPVAR
A = $TMPVAR
call println
add TMPVAR, 1
cmp TMPVAR, 9
jne .reloop
Last edited on
closed account (EzwRko23)
ROmai - no.

Chrisname, it does not work this way. There is no temporary variable in Scala like $_ in Perl.
"println" is a one argument function of type "Int => Unit" here. "foreach" requires a function as its argument and calls it for every item in the collection. Unlike in Perl, this works also for functions with more arguments e.g.:

1
2
def add(a: Int, b: Int) = a + b     // just for demonstration purpose
println(1 until 9 reduceLeft add)   // prints out 36 (= 1 + 2 + 3 + .. + 8) 


However, I could write it simpler:
 
println(1 until 9 reduceLeft (_ + _))

Last edited on
Oh. Oh well.
I can do what you did in scala in c++ in one line
Besides preprocessor statements, you can essentially write all code on one line in C++. This doesn't make debugging easier for compilers that don't tell you a column number, though.
I know L B, that was the joke.
closed account (S6k9GNh0)
Have you ever had someone try and write a one lined program because they thought it was required? I have!

Out of honesty though, I remember finding myself reformatting a lot of the code posted on the forums from beginners just so everyone else and myself could read it without our heads exploding. Especially in a group of coders, they will always gripe and complain if you put in very poorly formatted code.
Pages: 12