Olena 0.10 Coding Style

From LRDE



To keep the code homogeneous and "easy" to read, any patch for Olena 0.10 should respect some rules. Several of them come from the style guidelines of the libstdc++: http://www.sunsite.ualberta.ca/Documentation/Gnu/libstdc++-2.90.8/html/17_intro/C++STYLE .

This page is only a draft, all justified comments will be highly appreciated.


Template indentation

  • Choice
 1 template <class T>
 2 struct foo
 3 {
 4 };
 5 
 6 // use typename if T includes non class types such as "int"
 7 template <typename T>
 8 struct foo
 9 {
10 };
11 
12 and not 
13 
14 template <class T> 
15 struct foo {
16 };
17 
18 or 
19 
20 template <class T> struct foo {
21 };
  • Justifications

From the libstdc++ library.

Function declaration indentation

  • Choice

Always let the function name on a single line :

 1 static int
 2 foo()
 3 {
 4 }
 5 
 6 and not 
 7 
 8 static int foo()
 9 {
10 }

especially when the return type is rather long:

1 template <class T>
2 my_good_traits<T>::return_type
3 foo()
4 {
5 }
  • Justifications

Having the function name on one line has several advantages. First, with a simple grep "^functioname", it's easy to find the definition of a function. Moreover, when returns types are long or obfuscated, which is often the case in Olena, it keeps the function name and arguments easy to read.

Function calls and declarations parenthesis rules

  • Choice
 1 void
 2 foo(a, b) /* no space before the parenthesis */
 3 {
 4 }
 5 
 6 foo(a, b)
 7 
 8 and not
 9 
10 foo (a, b)
11 foo (a,b)
12 foo( a, b )
  • Justifications

First, when "foo" and "(" sticks together, it looks like a function (like in mathematics); second, we are used to read such parenthesis (like this present one) but not like ( this other one ).

Having arguments being well separated looks good (so "a,b" is rejected).

Preferring foo(a, b) over foo( a, b ) is shorter and so stresses that it is an entity separated from its environment.

Method calls

  • Choice
1 obj.m(...)
2 
3 and not
4 
5 obj . m
6 obj. m
  • Justifications

Not an intrinsics one, that is, the same as for function calls.

Type declaration

  • Choice

All lowercase, eg:

1 class point;
2 
3 template <class E>
4 class image;
  • Justifications

99% of use cases are declarations such as "point p;" and there is no ambiguity (a declaration follows "type var;").

'point' cannot be a good name for a variable. A "good" name for a variable is p, p1, cur_p, current_p or p_prime, that is, a name that explains what is the particular point in the algorithm. Having a point named 'point' does not hold enough information (if there's no information to give about a particular point then call p this point!)

'point' cannot conflict with another type name since we use namespace. 'point' is in fact 'oln::point'.

This choice is the one of the C++ std lib. All these justifications go for std::list!

The simplest the best.

With modern editors there are different highlighting colors for types and variables.

Writings such as type_something are longer and does not lead to more explicit code. I claim that "point_t p;" is less easily readable (parsable by human eyes) than "point p;". This question is equivalent to the one of "type* var_ptr / type& var_ref / type var" (a fashion that is now obsolete because code was more complex to read than explicit). The compiler avoids the programmer to confuse var->x and var.x that the same for types v. variables!

Declarations with modifed types (*, &)

  • Choice
1 type* var;
2 type& var;
  • Justifications

On the left (before the space delim) the precise type, on the right the variable name. This justification is the one that makes this convention being well-spread.

Variable names are easier to read (by human eyes) and we are going to use them (not their type names).

Macro on types returning types

  • Choice
1 oln_point_type(I) p;
2 oln_value_type(I) val;
3 ntg_value_type(u_int8) v;
  • Justifications
    • no namespaces for macros ==> how can the user determine the

origin of a macro ? In C, people used to prefix any functions with the project name, "simulating" namespaces. We are in this case with macro yet. And there is a high risk of clashes with user of other libraries macros. Indeed, if libraries such as Boost applied the same convention (ie. without prefix), there would be many clashes I think. So this approach does not seem quite reliable.

    • We need to specify the kind of thing the macro returns, so we need a

suffix (_type of _val). Indeed, there are several cases where the same macro name can refer to different kind of objects.

We cannot escape from these 2 constraints. Thus, the only choice left concerns letter cases:

1 oln_Point_type(I)
2 Oln_Point_Type(I)
3 oln_point_type(I)
4 OLN_POINT_TYPE(I)
5 // many other variants possible

The all caps version has the advantage to be commonly admitted to warn the user that it is a macro. Indeed, historically there is a difference between sqr(i) and SQR(i). On one hand, the user knows that it is a "real" function call so she knows that it's safe to write sqr(++i). On the other hand, it's a macro so she has to be careful when using it. This style convention has been settled to warn the user when the square root function is defined by a macro. I guess that this is the only justification of upcases for macros.

This justification does not hold for our macros since they apply on type(s)!

So we can choose the more readable version, which appeared to be all lower case.

Macros on types returning values

  • Choice
1 int dim = oln_dim_val(I);
2 int max = ntg_max_val(u_int8);
  • Justifications

Coherent with macros on types returning types convention.

Traits returning types

  • Choice
    • Dedicated traits (1)
 1 value_type<T>::ret v;
 2 point_type<T>::ret p;
 3 
 4 // and NOT
 5 
 6 value_type<T>::ret_t; // WRONG
 7 value_type<T>::res; // WRONG
 8 value_type<T>::return_type; // WRONG
 9 
10 value<T>::ret; // WRONG
    • Grouping traits (2)
1 traits<T>::value_type;
2 traits<T>::point_type;
3 
4 // and NOT
5 
6 traits<T>::value; // WRONG
7 traits<T>::value_t; // WRONG
  • Justifications

For (1), we know that the return value will be a type, so the shortest syntax is the best one (value_type<T>::ret). ret is more commonly used than res, so we prefer ret.

For (2), traits<T>::value_type gives informations about the type of the returned thing. xxx_t looks too close from the std::*_t reserved types.


Traits returning values

  • Choice
    • Dedicated traits (1)
1 dim_val<T>::ret
    • Grouping traits (2)
1 traits<T>::dim_val
  • Justifications

To be coherent with traits returning types.

Comments

  • Choice
 1 /*-------.
 2 {| class="wikitable"
 3 |-
 4 | foobar 
 5 |}
 6 
 7 `-------*/
 8 
 9 //! Brief description of Foobar
10 /*!
11   This is the complete description of the foobar class, bla bla bla.
12   The second line starts here.
13   blablabla.
14 */
15 struct foobar
16 {};
  • Justifications

These are comments in doxygen style, I find them quite clear and using them will help us if we decide to use doxygen on the future. The box containing the name of the class is really easy to create with a well configured emacs, and facilitate the reading of long headers I think.