[dev] [sbase] style

From: Evan Gates <evan.gates_AT_gmail.com>
Date: Mon, 17 Nov 2014 13:24:21 -0800

sbase has no unified style. Many things change from file to file. I am
more annoyed by this than I should be. I propose a style document for
sbase. I have included a starting point in order to promote
discussion. You will disagree with some of these points. Speak up and
explain your alternative and reasons. In the end it's up to the
maintainers to decide what the rules are, if there are any. I just
want to get the ball rolling.

My starting suggestions follow,
emg


recommended reading
===================
http://doc.cat-v.org/bell_labs/pikestyle

whitespace
==========
tabs for indentation
spaces for alignment
that means your code will always be aligned independent of tab size
one space before and after binary operators
no spaces between unary opterator and operand
no spaces around . and -> (see exceptions)
no tabs after first space on line
no trailing whitespace on line
spaces not tabs for multiline macros (we're aligning, our indentation
is 0 as that's where the statement (#define) starts)

blocks
======
all variable declarations at top of block
{ on same line preceded by single space (except functions)
} on own line except for continuation of statement (e.g. if else, do while)
no block for single statement (optional block? always block? discuss)
(what if inner statement uses block, braces outside? what if one of
two branches uses block?)

branches
--------
if (cond)
foo();
else {
bar();
baz();
}

or

if (cond) {
foo();
} else {
bar();
baz();
}

inner statement block
---------------------
if (p)
while (cond) {
foo();
bar();
}

or

if (p) {
while (cond) {
foo();
bar();
}
}


keywords
========
space after if/for/while/switch (it's not a function call)
no space after (
always use () with sizeof and no space (sizeof is like a function call)

variables
=========
declaration of pointer, * is adjacent to variable not type (as it's
part of the variable not the type, avoids int* i, j; etc.)

headers
=======
system headers (#include <...>) in alphabetical order
empty line
local headers (#include "...") in alphabetical order
if there is any reason to change order, comment to explain

variadic macros
===============
yay or nay?

file layout
===========
check dwm.c for example
leading comment with LICENSE notice and short explanation of file
headers
macros
types
function declarations
global variables
function definitions
main

comments
========
/* */ not //
short comments explaining what, not how, in order to quickly find relevant code

functions
=========
declarations at top of file
declarations, definitions, in alphabetical order (except main, at end of file)
static if not used outside current file (what's the right term?
compilation unit?)
definitions have modifiers and return type on own line
{ on own line (function definitions are special case of block as they
cannot be nested)

C version
=========
use C99 (why not C11? I really like anonymous unions/structs)
do not use for loop initial declarations (why?)
do not use // comments

types
=====
user defined types start with a capital letter
when possible typedef struct {} Name;

line length
===========
we aren't limited to 80 columns in our terminals anymore, no need to
pretend we are
if using more columns makes code more readable, do so
it also means we can fit more code on a single screen, less scrolling
(some hard limit so we don't have 300 character lines?)

tests (boolean)
===============
do not test against NULL explicitly (e.g. if (!p) instead of if (p == NULL))
do not test against 0 explicitly (e.g. if (!strcmp(p, q)) instead of
if (strcmp(p, q) == 0)) (discuss)
do not use bool type (helps prevent fallacies such as if (iscorrect() == TRUE))
do use compound assignment and test (e.g. if (!(p =
malloc(sizeof(Type)))) ...; )
unless you can assign at declaration (e.g. Type *p =
malloc(sizeof(Type)); if (!p) ...; )
(although that's more rare without mixed code and declarations, discuss)

switch
======
indent cases to same level as switch (i.e. do not indent the body of
the switch statement)
comment fall through cases

early returns/exits
===================
if needed use label + goto for cleanup instead of multiple nested
levels, however this can normally be avoided (discuss)
return/exit/fail early instead of using multiple levels of tests
do not clean up on fatal errors (just enprintf())
do not use an else/break/etc. after returning/failing

if (!p)
enprintf(2, "RTFM\n");
if (!q) {
fprintf(stderr, "still wrong, not fatal\n");
return -1;
}
...

instead of

if (!p)
enprintf(2, "RTFM\n");
else if (!q) {
fprintf(stderr, "still wrong, not fatal\n");
return -1;
} else {
...
}

exceptions
==========
exceptions to these rules can be made in order to make the code more
readable. e.g.:
(I think the exceptions will be the most contentious area. discuss)

remove linebreaks
-----------------
switch (a) {
case '1': foo(b); break;
case '2': bar(c); break;
case '3': baz(d); break;
default :
enprintf(2, "RTFM\n");
}

is more readable than

switch (a) {
case '1':
foo(b);
break;
case '2':
bar(c);
break;
case '3':
baz(d);
break;
default:
enprintf(2, "RTFM\n");
}

more alignment
--------------
somefunc(foo .bar, baz );
somefunc(bonzai.bar, qux );
somefunc(blah .bar, blargh);

more exceptions?
Received on Mon Nov 17 2014 - 22:24:21 CET

This archive was generated by hypermail 2.3.0 : Mon Nov 17 2014 - 22:36:15 CET