Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 340 lines (241 sloc) 11.362 kb
6f243c1 Björn Gustavsson Add coding guidelines for Erlang code
bjorng authored
1 The most important coding rule is to imitate the existing code
2 (that is always a good idea in any project you are contributing
3 to). If you add or modify code in existing modules, try to match
4 the style of the surrounding code in the module.
5
6 First a few general rules that perhaps go without saying:
7
8 - Make sure that your code compiles without warnings.
9
10 - Make sure that there are no calls to undefined functions.
11 In the Wings shell, use wx(). (Use wh() to show a list of
12 other useful utility commands.)
13
14 - This is not really a coding guideline, but don't forget
15 Bjorn's Law: "If it isn't tested, it doesn't work." This law
16 has proved itself to be correct many times in the fifteen years
17 or so since I formulated it. There is no change to the code
18 (or Makefile) that is so trivial that it can't possibly be wrong
19 and does not need testing.
20
21 - Don't sacrifice clarity for efficiency, unless it is truly
22 needed. Make sure that you measure (use the ?TC() macro) to
23 find the real bottleneck before you start optimizing. Even good
24 programmers are usually wrong when they try to guess where the
25 where the bottlenecks are located.
26
27 There some hints about efficiency in the guidelines below. For
28 more about efficiency, see
29
30 http://www.erlang.org/doc/efficiency_guide/part_frame.html
31
32 And now over to more concrete rules:
33
34 - Indent Erlang code using a mixture of tabs and spaces,
35 and interpret tabs as up to 8 spaces (this is the default
36 settings for the Erlang mode in Emacs).
37
38 It is also OK to indent using spaces only, if you use an
39 editor where it is difficult to mix tabs and spaces.
40
41 What is not OK is to change the definitions of tabs in your
42 editor, because that will make indentation look different
43 for everybody else.
44
45 - Each new level should be indented 4 more positions than
46 the previous one (default for the Erlang mode in Emacs).
47
48 - One percent character ("%") is used for comments *only* following
49 a line of code. Never place single percent characters at the
50 beginning of a line. Example:
51
52 -record(some_record,
53 {bar, %List of bar objects
54 foo %Keep track of the foos
55 .
56 .
57 .
58 }).
59
60 - Use two percent characters ("%%") for comment blocks before
61 a function or inside a function. Thus the percent characters are
62 either at the beginning of a line or preceded by white-space.
63 See src/wings_va.erl for the recommend way to comment exported
64 API functions.
65
66 - Use three percent characters ("%%%") for comments that apply
67 to more than one function. For instance like this:
68
69 %%%
70 %%% Local functions.
71 %%%
72
73 to indicate that the rest of the file contain local functions.
74
75 - Try to use at most 80 characters per line.
76
77 - Never comment out deleted code. Delete it from the file. We
78 use Git to keep track of the history of the file. Explain in
79 the check-in comment why you deleted the code. (The only
80 acceptable exception is *frequently* used io:format/2 calls used
81 for debugging.)
82
83 - Place the exported functions (and no local function) at the
84 beginning of the module. Local functions should follow all exported
85 functions. (This rule apply to new modules. Do not change all modules
86 that break that rule at once. We will do it step-by-step when doing
87 other changes to avoid huge diffs in the Git repository.)
88
89 - Place one blank line between each function definition, except possibly
90 for related one-line functions.
91
92 - Do not use -import. Use fully qualified calls -
93 Module:Function(Arguments...) - instead.
94
95 - But do import functions (such as map/2, reverse/1, and foldl/3) from
96 the 'lists' module. Importing those functions (that can be thought
97 of being part of the language) improves readability so much that
98 it justifies breaking the general rule. Further justification:
99 Robert Virding does it this way. (Robert Virding is one of the
100 original inventors of Erlang.)
101
102 - Also import min/2 and max/2 from the 'erlang' module for the
103 same reason.
104
105 - Commas in function heads and function calls should be followed
106 by one space. Example:
107
108 g(A, B, C) ->
109 A + g(B, c).
110
111 - Don't use any space after commas in terms and records. Example:
112
113 {ok,[1,2,3]}
114
115 - Don't use spaces around '=' in records.
116
117 - When you want to match and bind a variable at the same time in a
118 function head or case clause, put the pattern before the variable,
119 and no spaces around the '='. Example:
120
121 foo(#edge{vs=Va,lf=Lf}=Rec) ->
122 ...
123
124 - Never use is is_record/2. Match the record directly instead:
125
126 bar(#we{}=We) ->
127 ...
128
129 The Erlang compiler usually generate better code if the
130 record is matched directly, especially if there are other
131 clauses that match other records or data structures.
132
133 - Prefer matching out variables from records like this
134
135 foobar(Face, #we{fs=Ftab0}=We) ->
136 case gb_trees:get(Face, Ftab0) of
137 ......
138
139 instead of using the Rec#record.field syntax
140
141 foobar(Face, We) ->
142 case gb_trees:get(Face, We#we.fs) of
143 ...
144
145 The Erlang compiler usually generates better code in the former
146 case. Especially avoid using the Rec#record.field in guards, as
147 the Erlang compiler usually generates terrible code. That is,
148 do NOT write:
149
150 bad_idea(We) when We#we.id > 0 ->
151 ...
152
153 - Spread out record definitions on multiple lines with each field
154 name on separate line and comment each field with a comment
155 on the same line.
156
157 - Atom and function names consisting of several words should be
158 written in lowercase and combined with underscores ('_').
159 Example: long_atom_name
160
161 - Variable names consisting of several words should be written in
162 CamelCase, that is, the first letter of each word should be in
163 uppercase and the words should be joined together without spaces.
164 Example: VariableInCamelCase
165
166 - Frequently used variables are better kept short, to avoid having
167 to break too many lines. Try to use the existing conventions
168 instead of inventing your own. Common names to hold entire
169 records are:
170
171 We to hold a #we{} record
172 St to hold a #st{} record
173
174 Common names for record fields are:
175
176 #we{fs=Ftab,es=Etab,vp=Vtab}
177
178 #edge{vs=Va,ve=Vb,lf=Lf,rf=Rf,
179 ltpr=Ltpr,ltsu=Ltsu,rtpr=Rtpr,rtsu=Rtsu}
180
181 If you have no better names (more specific), use [H|T] for
182 matching out the head and tail of a list (there is no reason to
183 use longer names such as [Head|Tail] and [First|Rest]).
184
185 - When naming variables, atoms, and functions, prefer pronounceable
186 names. Avoid names such as "Btn" (short for "Button") and "Mnu"
187 (short for "Menu") which were constructed by removing vowels from
188 a single word.
189
190 Accepted abbreviations such as HTML is OK to use in variable names,
191 as are new abbreviations constructed by taking the first letter of
192 several words (e.g. "Lf" which stands for "Left Face").
193
194 Naming is the hardest thing in programming (at least for me) and in
195 the end you will just have to use your common sense to come up
196 with good names.
197
198 - Don't look into abstract/opaque data types. For instance, do NOT
199 write like this
200
201 ugly_selected_element(#st{sel=[{Id,{1,Element,_,_}}]}=St) ->
202 do_something(Id, Element, St);
203 ugly_selected_element(_) ->
204 wings_u:error("Only select a single element.").
205
206 to implement a command that only accepts a selection containing
207 a single element. Breaking abstractions is not acceptable. You
208 will just have to bite the bullet and write:
209
210 selected_element(#st{sel=[{Id,Sel}]}=St) ->
211 case gb_sets:to_list(Sel) of
212 [Element] ->
213 do_something(Id, Element, St);
214 _ ->
215 mul_sel_error()
216 end;
217 selected_element(_) -> mul_sel_error().
218
219 mul_sel_error() ->
220 wings_u:error("Only select a single element.").
221
222 Common abstract data types in the standard libraries are
223 gb_trees, gb_sets, array, dict, and sets. In Wings, we have
224 the wings_va module that must be used for all manipulation of
225 vertex attributes.
226
227 - Use existing APIs and libraries. Don't write new code to
228 manipulate common data structures before doing a serious attempt
229 to find out whether there is existing functionality that can
230 solve your problem.
231
232 - Never use size/1; use either tuple_size/1 or byte_size/1.
233
234 - Don't use lists:keysearch/3; use lists:keyfind/3 (introduced
235 in R13B) which eliminates the outer '{value,...}' tuple.
236
237 - Avoid 'and' and 'or'. They force you to use parenthesis around
238 the conditions
239
240 (A =:= B) and (C =:= D)
241
242 Instead, use comma (for 'and') or semi-colon (for 'or') in guards
243
244 f(A, B, C, D) when A =:= B, C =:= D ->
245 ...
246
247 For Boolean expression outside of guards, prefer 'andalso'/'orelse':
248
249 case A =:= B andalso C =:= D of
250 false -> ...'
251 true -> ...
252 end
253
254 Only use 'and' or 'or' if it is important that the right-hand side
255 is evaluated. For instance, the following expression
256
257 true or length(L) > 1
258
259 will cause an exception if L is not bound to a list, while
260
261 true orelse length(B) > 1
262
263 will never cause an exception.
264
265 'and' and 'andalso' will in general only behave differently when they
266 are nested inside another Boolean expression or in a negated Boolean
267 expression. For example, the following expression
268
269 not (false and (length(L) > 42))
270
271 will behave differently from
272
273 not (false andalso length(L) > 42)
274
275 when L is not bound to a list.
276
277 - Only use 'andalso'/'orelse' in guards when ',' and ';' cannot say
278 what you want to say. For example, do not write
279
280 foo(A, B) when A =:= 7 orelse B =:= 42 ->
281 ...
282
283 when
284
285 foo(A, B) when A =:= 7; B =:= 42 ->
286 ...
287
288 will do just fine.
289
290 - When you need several variable names in order to update a data
291 structure, number using "0" as suffix for the first instance.
292 Example:
293
294 update(We0) ->
295 We1 = some_update(We0),
296 We2 = some_other_update(We1),
297 We = penultimate_update(We2),
298 final_update(We).
299
300 - Note the difference between '==' and '=:=':
301
302 2 == 2.0 returns 'true'.
303 2 =:= 2.0 returns 'false'.
304
305 In matching, '=:=' is used implicitly. So given the following
306 function definition
307
308 equal(Same, Same) -> true;
309 equal(_, _) -> false.
310
311 calling cmp(2, 2) will return 'true' and cmp(2, 2.0) returns
312 'false'. So to be consistent with matching, you must use the
313 '=:=' operator.
314
315 On the other hand, the '<', '>', '=<', and '>=' operators all
316 behave similar to '=='. Therefore, in the following function
317
318 cmp(A, B) when A < B -> less;
319 cmp(A, B) when A == B -> equal;
320 cmp(A, B when A > B -> greater.
321
322 the operator in the second cluase must be '==' and not '=:='.
323 If the function was defined like this
324
325 bad_cmp(A, B) when A < B -> less;
326 bad_cmp(A, B) when A =:= B -> equal;
327 bad_cmp(A, B when A > B -> greater.
328
329 the call bad_cmp(2, 2.0) will cause 'function_clause' exception
330 because none of the clauses will match.
331
332 For non-numeric data types, '==' and '=:=' gives the same result,
333 but '=:=' is slightly faster.
334
335 To corresponding operators for testing non-equality are called
336 '/=' and '=/='.
337
338 I recommend using '=:=' and '=/=' unless there is a specific
339 reason not to.
Something went wrong with that request. Please try again.