summaryrefslogtreecommitdiff
path: root/doc/code-style.txt
blob: 2d125983d0185c206f1f1b2c20486ca8b3b6ea51 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
Waffle's coding style is heavily influenced by the Linux kernel and XCB.

When in doubt, follow the style of nearby code.


Naming
======

All symbols exposed in the public API must be prefixed with `waffle_` or
`WAFFLE_`.

No camelCase, itIsSoHardToRead, especiallyWhenTheVariableNameContainsAnUpperCaseAcronym.

Function and variable names are lower_case_with_underscores.

Enum and macro names are UPPER_CASE_WITH_UNDERSCORES.

Don't use typedefs without a strong reason. They more often degrade code's
readability than improve it.

Balance abbreviation with readability. A variable named number_of_objects is
too verbose; nobjs is too obscure; num_objects and num_objs are just right.


Object orientated design
========================

Much of Waffle's code adheres to an object oriented design. Not only does this
influence Waffle's architectural design, but also its naming conventions and code
organization.

For this discussion, we will use `struct waffle_window` as an example. It is
implemented in the files

    /include/waffle/waffle_window.h
    /src/waffle/api/waffle_window.c

A class's header and source file have the same name as the class. For example,
waffle_window.h and waffle_window.c.

Method names follow the convention of `typename_operation`. This makes it
immediately obvious on what the function acts and in which file the function
is defined.

    good: waffle_window_create
    good: waffle_window_swap_buffers

    bad: waffle_create_window

If a function is a plain ole procedure, it follow the naming convention
`prefix_action_object`. The following example is taken from
/src/waffle/egl/egl_no_template.c.

    good: egl_create_config
    bad:  egl_config_create // this looks like a method

A method's first argument is the object on which it acts, and is named 'self'.
Exceptions are "static" methods, such as creation methods. This makes it
immediately obvious which argument is the object acted upon.

    good:
        struct waffle_window*
        waffle_window_create(const char *name);

        bool
        waffle_window_swap_buffers(struct waffle_window *self);
                                                         ^^^^

    bad:
        bool
        waffle_window_swap_buffers(struct waffle_window *window);


Comments
========

Non-Doxygen comments begin with double '/'. Do not use '/*'-style comments.
There are special exceptions, such as when commenting items in a table. Use
your judgement.


Doxygen
-------

Waffle uses Doxygen as a documentation generator. Doxygen comments begin with
triple '/' and use '@' as the Doxygen command prefix.

    /// @brief Make fantastic coffee with rainbows and strawberries.
    ///
    /// Only drink one cup per day. Otherwise, you may become too happy.
    void
    make_fancy_coffee(
        struct coffee_mug *mug,
        struct french_press *press,
        struct sugar_dish *sugar);

Separate the brief and full description with a newline, as above. Otherwise,
Doxygen becomes confused and coalesces the full into the brief.


Commenting branches
-------------------

If a comment only applies to one branch of an if-statement, place the comment
in the branch. Otherwise, the code will repeats itself.

    good:
        if (dishes_need_washing && time >= 2300) {
            // It's too late to wash dishes. Defer them until morning.
            defer_washing_dishes();
            sleep();
        }
        else {
            // Even if the dishes need washing, it's too early to be worried
            // by them. Go do something fun.
            ride_a_bike();
        }

    bad:
        // If the dishes need washing, but it's too late to wash them, then
        // defer them until morning.  Otherwise, go do something fun. Even if
        // the dishes need washing, it's too early to be worried by them.
        if (dishes_need_washing && time >= 2300) {
            defer_washing_dishes();
            sleep();
        }
        else {
            ride_a_bike();
        }


Indentation
===========

Indent 4 spaces. No tabs.

Place a function's return type on its own line. This ensures that all function
names are aligned and makes it easier to quickly find a function when scanning
the source.

    void
    make_coffee(int x, int y);

If a function prototype has a longwinded parameter list, then indent it like this:

    void
    make_fancy_coffee(
        struct coffee_mug *mug,
        struct french_press *press,
        struct sugar_dish *sugar);

When calling a function with a longwinded argument list, indent it in either
of two ways.

    do_amazing_incredible_thing_with_a_really_long_function(
                                            rainbows,
                                            unicorns,
                                            strawberries,
                                            unicycle);

    do_boring_thing(rocks,
                    toothbrush,
                    dust_pan,
                    traffic_jam);

Indent cases in switch statements. The last case always requires a jump
(break, return, goto).

    switch (time) {
        case 600:
        case 1545:
            wake_up();
            break;
        case 1500:
        case 2200:
            sleep();
            break;
        default:
            breathe();
            break;
    }

Don't put multiple statements on a single line.

    if (condition) do_something;
    to_do_or_not_to_do;


Braces
======

For all statements that require braces, the opening brace is on the same line
as the statement, except for function definitions, where the brace is on a
line of its own.

    if (condition) {
        do_stuff();
    }

    void
    make_fancy_coffee(
        struct coffee_mug *mug,
        struct french_press *press,
        struct sugar_dish *sugar)
    {
        rush_or_be_late_to_work();
    }

The closing brace is always on a line of its own.

    if (x) {
        ...
    }
    else if (y) {
        ...
    }
    else {
        ...
    }

and

    do {
        ...
    }
    while (condition);


Spaces
======

Leave no trailing whitespace on end of lines. This can cause spurious commit
conflicts.

A single empty line separates function and struct defintions.

Do not add spaces inside a parenthesized expression.

    bad: foo( x, y );

Place a space after these keywords:
    if, switch, case, for, do, while

For keywords that are typically used as functions, do not follow the keyword
with a space and do enclose the arguments with parentheses. The keywords are:
    sizeof, typeof, alignof, __attribute__

When declaring a variable or argument with pointer type, the '*' goes adjacent
to the variable or argument name.

    void
    make_fancy_coffee(
        struct coffee_mug *mug,
        struct french_press *press,
        struct sugar_dish *sugar)
    {
        void *mystery_ingredient = mug + press + sugar;
        ...
    }

No spaces around unary operators.
    --y;
    !z;

No spaces around the structure member operators: '.' and '->'.
    cow->tail
    teapot.spout

Place a single space before and after the binary operators.
    a + b
    x == y