These articles are written by Codalogic empowerees as a way of sharing knowledge with the programming community. They do not necessarily reflect the opinions of Codalogic.
I've been reading a lot of third-party code lately and it has reminded me that my coding style is quite different to that of many.
Before you shout "Yuck" and dismiss the code examples I'd like to explain the rationale behind it. (Don't worry, I'm happy to conform to any coding style for the right money :) )
Many practitioners say that we should optimise our code layout for reading rather than writing because we spend more time reading code than writing it.
I think we should take this one step further. We should also optimise our code for scanning.
We spend a lot of time scanning our code for the bit we need. We also want to be able to scan code for the general gist of it without looking at it in a detailed way.
Quite often you see code like this:
foo(!assign);
With a quick scan it's difficult to see where the function name ends and the variable name begins.
It's also likely you will miss the !
completely.
I therefore prefer to spread things out a bit more. Left to my own devices, I would do:
foo( ! assign );
This makes it easier to see the use of assign
which might be hard to see when doing a quick scan with the earlier
layout, and also makes the !
clearer.
Generally I try to lay out the special characters as if they were alphabetic words - giving them space either side.
So for references in function arguments I would do:
void foo( const std::string & name ) ...
void bar( const char * type ) ...
Ideally I will put all the function arguments on one line. But if the line ends up too long I will put each argument on a separate line rather than having multiple arguments on multiple lines:
void foo(
const std::string & name,
const char * type )
I don't attempt to line up the start of the arguments with the end of the function name because if I want to change the function name I will have lay stuff out again. That's just needless busy work. They are aligned to one or two tab stops after the start of the function name.
I put the return type on the same line as the function name. I find the blank space above the function name that precedes it makes the function names easier to pick out.
So instead of:
void
foo( const std::string & name )
I do:
void foo( const std::string & name )
I appreciate that you can probably train your eye to cope with either of the above two layouts, but I currently find the latter easier.
I don't do "east return". I figure by the time I've read auto
I might as well have read int
or std::string
and
learnt something useful about the function. (In templates where east return is useful is another matter.)
Similarly I'm still a "west const" guy. I find east const only really helps with things like
char const * const
. Mostly I don't use pointers so prioritising that layout for that situation doesn't work for me.
As an English speaker I'm accustomed to the adjective coming before the noun so const Bar
works
much better for me. If you know the trick of reading east const backwards then you can also work out
how to read the west const layout if the need arises. Plus I think being generous with the use of const
and making it clear when it is used makes for better code. (Although concepts on function arguments may throw a
spanner in the works here.)
Some people will layout variables and other code similar to the following:
int i = 0;
std::string context = "Start";
LineContextHandler primary_line_handler = get_handler();
IMO that looks great from the other side of the room but is hard to maintain if you change the longest line and it's also hard to associate a variable with its value when there are lots of them.
Instead I just do:
int i = 0;
std::string context = "Start";
LineContextHandler primary_line_handler = get_handler();
Not as pretty but easier to maintain and easier to read.
For if()
blocks I also like to space things out similar to elements in function declarations.
The following makes the !
pretty unmissable:
if( ! assign && ! settable )
I tend to not leave a space between the if
and the (
(despite that being a convention since
Kernighan & Ritchie) because when I space out the other stuff the leading (
looks a bit lonely
and having introduced the if
there's no need to bring additional attention to the opening
(
. I guess the layout could be confused with suggesting the start of a function but I've never had that
problem.
Similarly, the brackets in something like the following looks a bit flimsy and spacing them out doesn't add any value:
if( ( ( ! a && b ) || ( c && d ) ) )
So I would combine adjacent brackets:
if( (( ! a && b ) || ( c && d )) )
In terms of if()-else if()-else
blocks, I don't reason that as a single construct. Instead
I reason about each part as a conditionally executed block. I would therefore lay it out as:
if( ! assign && ! settable )
{
phase( 1 );
}
else if( ready() )
{
phase( 2 );
}
else
{
phase( 3 );
}
The else
-ness then becomes part of the condition for executing the subsequent block.
An exception might be:
if( ! assign && ! settable )
phase( 1 );
else
phase( 3 );
In terms of brace layout I tend to adopt whatever is the language prefered layout if there is one.
I prefer 4 spaces per tabstop instead of 2 so that I can see the indenting better. (If we're supposed to be avoiding excessive nesting we should probably have 20 space nesting!)
Another non-conformist practice is to put the private data members of a class at the top rather than the bottom. I find if I want to understand how a class works, knowing the data members is vital. Having to scroll to the bottom of a class and then back up is very inefficient IMO. Usually a class won't have many data members, so they are usually very easy to skip over if I'm not interested in them.
I accept that my coding style may look weird and unconventional to many but I hope this post has shown that there is rationale to it even if you don't agree with my choices. And rest assured, if you want me to write code in a specific way, I will.
February 2023
January 2023
December 2022
November 2022
October 2022
September 2022
August 2022
November 2021
June 2021
May 2021
April 2021
March 2021
October 2020
September 2020
September 2019
March 2019
June 2018
June 2017
August 2016