Skip to content

Instantly share code, notes, and snippets.

@markusfisch
Last active June 29, 2019 00:56
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save markusfisch/e4cf70fab43e798f6091 to your computer and use it in GitHub Desktop.
Save markusfisch/e4cf70fab43e798f6091 to your computer and use it in GitHub Desktop.
What coding style works for me

What works for me

This is a reflection of my coding style. What I have found to work for me.

As everything in this universe, nothing is final. Change is an inherent property of this world. And there are many equally good ways to get to Rome.

In general, I think a good style should enhance readability while having as few exceptions as possible.

In a nutshell

Brief example

int sum_characters( char *s )
{
	int sum = 0;
	char *p;

	if( !s )
		return -1;

	for( p = s; *p; ++p )
		sum += *p;

	return sum;
}

int main( int argc, char **argv )
{
	while( --argc )
		printf(
			"%s = %d\n",
			*++argv,
			sum_characters( *argv ) );

	return 0;
}

Rationale

I'm always consistent

Sticking to a typographic convention improves readability.

Reading code means following thoughts. Using different conventions for the same thing breaks focus and makes understanding harder.

For example, if a project uses "camelCase", I won't use underscores.

More profound arguments for consistency can be found in Notes on Programming in C.

I use only tabs to indent

To me, a tab is a level of indent from the left document edge.

So, I never use tabs anywhere except at the beginning of a line.

I use one space character to separate words in a line. I don't align assignments vertically. So there's no need to use more than one space character at a time.

And because of all this, I never mix spaces with tabs.

Tabs indent lines. Spaces separate words.

This way, every reader can pick their own tab width and, because I try to avoid indenting more than 3 levels, the code has a fair chance to look fine everywhere.

Put another way, working with tabs responsibly is the most simplest way to indent. I don't have to use many characters where one is enough.

Preferring spaces over tabs because they are thought to be more fool proof is like choosing a club instead of a sword because you may cut yourself. I go with the sword because I know how to handle it.

I use only one space character to separate words

One space character is enough white space for all situations.

Using more than one space character doesn't improve readability and would require more rules without adding value.

I use only one level of indent at a time

By using only one level no matter what, there's only one rule for all the things that need indent.

For example, I always indent continuation lines from the beginning of the line and never from the last opening brace:

initialize_flux_capacitor(
	foo,
	bar );

Which encourages semantic symbol names without having very deep indents.

Nested example:

if( foo == 1 &&
	bar == 2 &&
	do_something(
		foo,
		bar ) )
{
	...
}

Using only one level of indent is always simple and clear.

I don't align assignments vertically

In the beginning, everything looks nice and clean:

double alpha = 4.37;
double beta  = 63.4;

But as things get more complicated, it just gets harder to read and edit:

double alpha_centauri = 4.37;
double beta_pictoris  = 63.4;
char   *name          = "name";
int    i              = 0;

Vertical alignment doesn't scale, takes time and effort and doesn't make things much more readable. Compare the block above to this:

double alpha_centauri = 4.37;
double beta_pictoris = 63.4;
char *name = "name";
int i = 0;

I think the latter is easier to read because the symbol and the value are always next to each other. And it's easier to maintain because I don't have to edit as much for a new variable.

And since I always try to allocate/declare a variable in the tightest possible scope, I usually don't have large declaration blocks anyway.

I put opening and closing braces on their own line

I think the reason why K&R put the opening brace at the end of the line was readability.

On a traditional computer screen with 25 lines it is very reasonable to try to make the most of those 25 lines. Putting the opening brace at the end of the line is a way to do that.

But now it is a new millennium and there are no more ANSI terminals and we have much more lines.

A classical ANSI terminal was roughly 14" wide. That means, those 25 lines were big on screen. With lines that big, source code is very readable with the opening brace at the end of the line. This is the context where 1TBS makes sense.

But today, a line is much smaller on screen and putting curly braces on their own line improves readability by adding white space.

Another reason is, that in most C-like languages, curly braces define a scope by themselves:

{
	int n;

	for( n = foo; n--; )
		bar( n );
}

So always putting the opening brace on their own line gives just one rule for all situations.

For parenthesis, I use an inner padding of one space character

I think the parenthesis belongs to the expression. You can't have an "if" statement without parenthesis for example (speaking of C-like syntaxes).

Visually separating the argument from the keyword/function/method also reflects my pattern of thinking:

I want to invoke foo() with argument bar. foo() and bar are two things I want to have visually separated.

So, for me, separating statement and argument improves readability:

if( a == b )
	foo( bar );

Also, I don't want to confuse arithmetical parenthesis with syntactic parenthesis. Because arithmetical parenthesis have a very different meaning - they clearly don't belong to a statement - I don't pad those and use them only where necessary:

n = (n+3)*3;

It's quite popular, to add padding before parenthesis for keywords but no padding for function definitions and calls:

void main(int argc, char **argv) {
	for (; argc--; ++argv)
		printf("%s\n", *argv);
}

I see no value in having two rules where one is enough.

I put commas and operators at the end of a line when breaking a line

For me commas and operators belong to the end of the line to "mark" them visually as "not finished". Of course, that's especially obvious for C-like languages where you need to finish every statement with a semicolon.

Following that thought, I think

foo = calculate_alpha()+
	calculate_beta()+
	3.1415;

is more readable than

foo = calculate_alpha()
	+calculate_beta()
	+3.1415;

In the first case, you can't confuse an operator with a sign and the line break gives the reader an idea of what to do with the next line.

I break lines at ~80 columns

Very long lines make a reader loose context between long and short lines.

So instead of something like this:

printf( "%02d %08x %s:%s %s (%s)\n", index, code, name, module, short_message, long_message );

I prefer this:

printf(
	"%02d %08x %s:%s %s (%s)\n",
	index,
	code,
	name,
	module,
	short_message,
	long_message );

A glance is enough to see what's going on. I don't have to scroll and I don't have to check the far end of the line.

But why 80?

80 columns are common ground. 80 columns fit (almost) everywhere. In a terminal, on most screens (even smartphones), on a web page and even in your fancy IDE with all its side pannels open.

Not breaking lines simply makes code harder to follow.

I prefer a pragmatic approach

Very often, I tried to do far too much. And very often, I tried to be too clever.

And that never worked out too well.

Trying to foresee the future can lead to very complex programs. Unnecessarily complex for the task at hand. And eventually, not as flexible as intended.

So the simplest approach is always the best to start with.

I try to focus on data structures and write simple code.

Writing simple code gives understandable code.

I always try to not make things more complex than they really need to be.

I use clear and simple semantics

The more public a symbol is, the more verbose it should be.

Finding a good, semantic name for a method or a function is very important. Take the time to really pin it down. It's really worth it.

Clear and semantic symbols make readable, understandable and intuitive code.

Of course, that doesn't mean I'm using a long name for a local, temporary counter variable.

But functions and methods, even when private, should always be designed as if they were an API.

I only comment what the code cannot say

Generally speaking, I only add comments to explain what I think cannot be immediately clear/obvious to someone else.

This means I use few, but meaningful comments. I don't explain the obvious.

Appendix

Your style is weird! Is there a way to convert automatically?

Sort of. You may use astyle with those arguments:

$ astyle \
	--suffix=none \
	--unpad-paren \
	--pad-paren-in \
	--style=allman \
	--indent-force-tab \
	--min-conditional-indent=0 \
	--max-instatement-indent=0 \
	[SOURCE_FILES]

Configure VIM to highlight misplaced tabs and spaces

Put this into your .vimrc to highlight tabs within lines and spaces in indents:

" Highlight tabs within lines, trailing whitespace and
" spaces at the beginning of lines
match errorMsg /[^\t]\zs\t\+\|\s\+$\|^[\t]*[ ]\+[\t]*[^\*]/
set noexpandtab

You'll instantly see, when and where somebody's mixing spaces with tabs.

@evandrix
Copy link

evandrix commented Nov 3, 2016

how are you doing --max-instatement-indent=0 ? i get errors with Artistic Style Version 2.05.1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment