aboutsummaryrefslogtreecommitdiffstats
path: root/doc/coding_style.md
blob: 17b7c03763f83537f6612d041463661ef58e3163 (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
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804

# Prosody Coding Style Guide

This style guides lists the coding conventions used in the
[Prosody](https://prosody.im/) project. It is based heavily on the [style guide used by the LuaRocks project](https://github.com/luarocks/lua-style-guide).

## Indentation and formatting

* Prosody code is indented with tabs at the start of the line, a single
  tab per logical indent level:

```lua
for i, pkg in ipairs(packages) do
    for name, version in pairs(pkg) do
        if name == searched then
            print(version)
        end
    end
end
```

Tab width is configurable in editors, so never assume a particular width.
Specically this means you should not mix tabs and spaces, or use tabs for
alignment of items at different indentation levels.

* Use LF (Unix) line endings.

## Comments

* Comments are encouraged where necessary to explain non-obvious code.

* In general comments should be used to explain 'why', not 'how'

### Comment tags

A comment may be prefixed with one of the following tags:

* **FIXME**: Indicates a serious problem with the code that should be addressed
* **TODO**: Indicates an open task, feature request or code restructuring that
  is primarily of interest to developers (otherwise it should be in the
  issue tracker).
* **COMPAT**: Must be used on all code that is present only for backwards-compatibility,
  and may be removed one day. For example code that is added to support old
  or buggy third-party software or dependencies.

**Example:**

```lua
-- TODO: implement method
local function something()
   -- FIXME: check conditions
end

```

## Variable names

* Variable names with larger scope should be more descriptive than those with
smaller scope. One-letter variable names should be avoided except for very
small scopes (less than ten lines) or for iterators.

* `i` should be used only as a counter variable in for loops (either numeric for
or `ipairs`).

* Prefer more descriptive names than `k` and `v` when iterating with `pairs`,
unless you are writing a function that operates on generic tables.

* Use `_` for ignored variables (e.g. in for loops:)

```lua
for _, item in ipairs(items) do
   do_something_with_item(item)
end
```

* Generally all identifiers (variables and function names) should use `snake_case`,
  i.e. lowercase words joined by `_`.

```lua
-- bad
local OBJEcttsssss = {}
local thisIsMyObject = {}
local c = function()
   -- ...stuff...
end

-- good
local this_is_my_object = {}

local function do_that_thing()
   -- ...stuff...
end
```

> **Rationale:** The standard library uses lowercase APIs, with `joinedlowercase`
names, but this does not scale too well for more complex APIs. `snake_case`
tends to look good enough and not too out-of-place along side the standard
APIs.

```lua
for _, name in pairs(names) do
   -- ...stuff...
end
```

* Prefer using `is_` when naming boolean functions:

```lua
-- bad
local function evil(alignment)
   return alignment < 100
end

-- good
local function is_evil(alignment)
   return alignment < 100
end
```

* `UPPER_CASE` is to be used sparingly, with "constants" only.

> **Rationale:** "Sparingly", since Lua does not have real constants. This
notation is most useful in libraries that bind C libraries, when bringing over
constants from C.

* Do not use uppercase names starting with `_`, they are reserved by Lua.

## Tables

* When creating a table, prefer populating its fields all at once, if possible:

```lua
local player = { name = "Jack", class = "Rogue" }
```

* Items should be separated by commas. If there are many items, put each
  key/value on a separate line and use a semi-colon after each item (including
  the last one):

```lua
local player = {
   name = "Jack";
   class = "Rogue";
}
```

> **Rationale:** This makes the structure of your tables more evident at a glance.
Trailing commas make it quicker to add new fields and produces shorter diffs.

* Use plain `key` syntax whenever possible, use `["key"]` syntax when using names
that can't be represented as identifiers and avoid mixing representations in
a declaration:

```lua
local mytable = {
   ["1394-E"] = val1,
   ["UTF-8"] = val2,
   ["and"] = val2,
}
```

## Strings

* Use `"double quotes"` for strings; use `'single quotes'` when writing strings
that contain double quotes.

```lua
local name = "Prosody"
local sentence = 'The name of the program is "Prosody"'
```

> **Rationale:** Double quotes are used as string delimiters in a larger number of
programming languages. Single quotes are useful for avoiding escaping when
using double quotes in literals.

## Line lengths

* There are no hard or soft limits on line lengths. Line lengths are naturally
limited by using one statement per line. If that still produces lines that are
too long (e.g. an expression that produces a line over 256-characters long,
for example), this means the expression is too complex and would do better
split into subexpressions with reasonable names.

> **Rationale:** No one works on VT100 terminals anymore. If line lengths are a proxy
for code complexity, we should address code complexity instead of using line
breaks to fit mind-bending statements over multiple lines.

## Function declaration syntax

* Prefer function syntax over variable syntax. This helps differentiate between
named and anonymous functions.

```lua
-- bad
local nope = function(name, options)
   -- ...stuff...
end

-- good
local function yup(name, options)
   -- ...stuff...
end
```

* Perform validation early and return as early as possible.

```lua
-- bad
local function is_good_name(name, options, arg)
   local is_good = #name > 3
   is_good = is_good and #name < 30

   -- ...stuff...

   return is_good
end

-- good
local function is_good_name(name, options, args)
   if #name < 3 or #name > 30 then
      return false
   end

   -- ...stuff...

   return true
end
```

## Function calls

* Even though Lua allows it, generally you should not omit parentheses
  for functions that take a unique string literal argument.

```lua
-- bad
local data = get_data"KRP"..tostring(area_number)
-- good
local data = get_data("KRP"..tostring(area_number))
local data = get_data("KRP")..tostring(area_number)
```

> **Rationale:** It is not obvious at a glace what the precedence rules are
when omitting the parentheses in a function call. Can you quickly tell which
of the two "good" examples in equivalent to the "bad" one? (It's the second
one).

* You should not omit parenthesis for functions that take a unique table
argument on a single line. You may do so for table arguments that span several
lines.

```lua
local an_instance = a_module.new {
   a_parameter = 42,
   another_parameter = "yay",
}
```

> **Rationale:** The use as in `a_module.new` above occurs alone in a statement,
so there are no precedence issues.

## Table attributes

* Use dot notation when accessing known properties.

```lua
local luke = {
   jedi = true,
   age = 28,
}

-- bad
local is_jedi = luke["jedi"]

-- good
local is_jedi = luke.jedi
```

* Use subscript notation `[]` when accessing properties with a variable or if using a table as a list.

```lua
local vehicles = load_vehicles_from_disk("vehicles.dat")

if vehicles["Porsche"] then
   porsche_handler(vehicles["Porsche"])
   vehicles["Porsche"] = nil
end
for name, cars in pairs(vehicles) do
   regular_handler(cars)
end
```

> **Rationale:** Using dot notation makes it clearer that the given key is meant
to be used as a record/object field.

## Functions in tables

* When declaring modules and classes, declare functions external to the table definition:

```lua
local my_module = {}

function my_module.a_function(x)
   -- code
end
```

* When declaring metatables, declare function internal to the table definition.

```lua
local version_mt = {
   __eq = function(a, b)
      -- code
   end;
   __lt = function(a, b)
      -- code
   end;
}
```

> **Rationale:** Metatables contain special behavior that affect the tables
they're assigned (and are used implicitly at the call site), so it's good to
be able to get a view of the complete behavior of the metatable at a glance.

This is not as important for objects and modules, which usually have way more
code, and which don't fit in a single screen anyway, so nesting them inside
the table does not gain much: when scrolling a longer file, it is more evident
that `check_version` is a method of `Api` if it says `function Api:check_version()`
than if it says `check_version = function()` under some indentation level.

## Variable declaration

* Always use `local` to declare variables.

```lua
-- bad
superpower = get_superpower()

-- good
local superpower = get_superpower()
```

> **Rationale:** Not doing so will result in global variables to avoid polluting
the global namespace.

## Variable scope

* Assign variables with the smallest possible scope.

```lua
-- bad
local function good()
   local name = get_name()

   test()
   print("doing stuff..")

   --...other stuff...

   if name == "test" then
      return false
   end

   return name
end

-- good
local bad = function()
   test()
   print("doing stuff..")

   --...other stuff...

   local name = get_name()

   if name == "test" then
      return false
   end

   return name
end
```

> **Rationale:** Lua has proper lexical scoping. Declaring the function later means that its
scope is smaller, so this makes it easier to check for the effects of a variable.

## Conditional expressions

* False and nil are falsy in conditional expressions. Use shortcuts when you
can, unless you need to know the difference between false and nil.

```lua
-- bad
if name ~= nil then
   -- ...stuff...
end

-- good
if name then
   -- ...stuff...
end
```

* Avoid designing APIs which depend on the difference between `nil` and `false`.

* Use the `and`/`or` idiom for the pseudo-ternary operator when it results in
more straightforward code. When nesting expressions, use parentheses to make it
easier to scan visually:

```lua
local function default_name(name)
   -- return the default "Waldo" if name is nil
   return name or "Waldo"
end

local function brew_coffee(machine)
   return (machine and machine.is_loaded) and "coffee brewing" or "fill your water"
end
```

Note that the `x and y or z` as a substitute for `x ? y : z` does not work if
`y` may be `nil` or `false` so avoid it altogether for returning booleans or
values which may be nil.

## Blocks

* Use single-line blocks only for `then return`, `then break` and `function return` (a.k.a "lambda") constructs:

```lua
-- good
if test then break end

-- good
if not ok then return nil, "this failed for this reason: " .. reason end

-- good
use_callback(x, function(k) return k.last end)

-- good
if test then
  return false
end

-- bad
if test < 1 and do_complicated_function(test) == false or seven == 8 and nine == 10 then do_other_complicated_function() end

-- good
if test < 1 and do_complicated_function(test) == false or seven == 8 and nine == 10 then
   do_other_complicated_function()
   return false
end
```

* Separate statements onto multiple lines. Do not use semicolons as statement terminators.

```lua
-- bad
local whatever = "sure";
a = 1; b = 2

-- good
local whatever = "sure"
a = 1
b = 2
```

## Spacing

* Use a space after `--`.

```lua
--bad
-- good
```

* Always put a space after commas and between operators and assignment signs:

```lua
-- bad
local x = y*9
local numbers={1,2,3}
numbers={1 , 2 , 3}
numbers={1 ,2 ,3}
local strings = { "hello"
                , "Lua"
                , "world"
                }
dog.set( "attr",{
  age="1 year",
  breed="Bernese Mountain Dog"
})

-- good
local x = y * 9
local numbers = {1, 2, 3}
local strings = {
    "hello";
    "Lua";
    "world";
}
dog.set("attr", {
   age = "1 year",
   breed = "Bernese Mountain Dog",
})
```

* Indent tables and functions according to the start of the line, not the construct:

```lua
-- bad
local my_table = {
                    "hello",
                    "world",
                 }
using_a_callback(x, function(...)
                       print("hello")
                    end)

-- good
local my_table = {
    "hello";
    "world";
}
using_a_callback(x, function(...)
   print("hello")
end)
```

> **Rationale:** This keep indentation levels aligned at predictable places. You don't
need to realign the entire block if something in the first line changes (such as
replacing `x` with `xy` in the `using_a_callback` example above).

* The concatenation operator gets a pass for avoiding spaces:

```lua
-- okay
local message = "Hello, "..user.."! This is your day # "..day.." in our platform!"
```

> **Rationale:** Being at the baseline, the dots already provide some visual spacing.

* No spaces after the name of a function in a declaration or in its arguments:

```lua
-- bad
local function hello ( name, language )
   -- code
end

-- good
local function hello(name, language)
   -- code
end
```

* Add blank lines between functions:

```lua
-- bad
local function foo()
   -- code
end
local function bar()
   -- code
end

-- good
local function foo()
   -- code
end

local function bar()
   -- code
end
```

* Avoid aligning variable declarations:

```lua
-- bad
local a               = 1
local long_identifier = 2

-- good
local a = 1
local long_identifier = 2
```

> **Rationale:** This produces extra diffs which add noise to `git blame`.

* Alignment is occasionally useful when logical correspondence is to be highlighted:

```lua
-- okay
sys_command(form, UI_FORM_UPDATE_NODE, "a",      FORM_NODE_HIDDEN,  false)
sys_command(form, UI_FORM_UPDATE_NODE, "sample", FORM_NODE_VISIBLE, false)
```

## Typing

* In non-performance critical code, it can be useful to add type-checking assertions
for function arguments:

```lua
function manif.load_manifest(repo_url, lua_version)
   assert(type(repo_url) == "string")
   assert(type(lua_version) == "string" or not lua_version)

   -- ...
end
```

* Use the standard functions for type conversion, avoid relying on coercion:

```lua
-- bad
local total_score = review_score .. ""

-- good
local total_score = tostring(review_score)
```

## Errors

* Functions that can fail for reasons that are expected (e.g. I/O) should
return `nil` and a (string) error message on error, possibly followed by other
return values such as an error code.

* On errors such as API misuse, an error should be thrown, either with `error()`
or `assert()`.

## Modules

Follow [these guidelines](http://hisham.hm/2014/01/02/how-to-write-lua-modules-in-a-post-module-world/) for writing modules. In short:

* Always require a module into a local variable named after the last component of the module’s full name.

```lua
local bar = require("foo.bar") -- requiring the module

bar.say("hello") -- using the module
```

* Don’t rename modules arbitrarily:

```lua
-- bad
local skt = require("socket")
```

> **Rationale:** Code is much harder to read if we have to keep going back to the top
to check how you chose to call a module.

* Start a module by declaring its table using the same all-lowercase local
name that will be used to require it. You may use an LDoc comment to identify
the whole module path.

```lua
--- @module foo.bar
local bar = {}
```

* Try to use names that won't clash with your local variables. For instance, don't
name your module something like “size”.

* Use `local function` to declare _local_ functions only: that is, functions
that won’t be accessible from outside the module.

That is, `local function helper_foo()` means that `helper_foo` is really local.

* Public functions are declared in the module table, with dot syntax:

```lua
function bar.say(greeting)
   print(greeting)
end
```

> **Rationale:** Visibility rules are made explicit through syntax.

* Do not set any globals in your module and always return a table in the end.

* If you would like your module to be used as a function, you may set the
`__call` metamethod on the module table instead.

> **Rationale:** Modules should return tables in order to be amenable to have their
contents inspected via the Lua interactive interpreter or other tools.

* Requiring a module should cause no side-effect other than loading other
modules and returning the module table.

* A module should not have state. If a module needs configuration, turn
  it into a factory. For example, do not make something like this:

```lua
-- bad
local mp = require "MessagePack"
mp.set_integer("unsigned")
```

and do something like this instead:

```lua
-- good
local messagepack = require("messagepack")
local mpack = messagepack.new({integer = "unsigned"})
```

* The invocation of require may omit parentheses around the module name:

```lua
local bla = require "bla"
```

## Metatables, classes and objects

If creating a new type of object that has a metatable and methods, the
metatable and methods table should be separate, and the metatable name
should end with `_mt`.

```lua
local mytype_methods = {};
local mytype_mt = { __index = mytype_methods };

function mytype_methods:add_new_thing(thing)
end

local function new()
    return setmetatable({}, mytype_mt);
end

return { new = new };
```

* Use the method notation when invoking methods:

```
-- bad
my_object.my_method(my_object)

-- good
my_object:my_method()
```

> **Rationale:** This makes it explicit that the intent is to use the function as a method.

* Do not rely on the `__gc` metamethod to release resources other than memory.
If your object manage resources such as files, add a `close` method to their
APIs and do not auto-close via `__gc`. Auto-closing via `__gc` would entice
users of your module to not close resources as soon as possible. (Note that
the standard `io` library does not follow this recommendation, and users often
forget that not closing files immediately can lead to "too many open files"
errors when the program runs for a while.)

> **Rationale:** The garbage collector performs automatic *memory* management,
dealing with memory only. There is no guarantees as to when the garbage
collector will be invoked, and memory pressure does not correlate to pressure
on other resources.

## File structure

* Lua files should be named in all lowercase.

* Tests should be in a top-level `spec` directory. Prosody uses
[Busted](http://olivinelabs.com/busted/) for testing.

## Static checking

All code should pass [luacheck](https://github.com/mpeterv/luacheck) using
the `.luacheckrc` provided in the Prosody repository, and using miminal
inline exceptions.

* luacheck warnings of class 211, 212, 213 (unused variable, argument or loop
variable) may be ignored, if the unused variable was added explicitly: for
example, sometimes it is useful, for code understandability, to spell out what
the keys and values in a table are, even if you're only using one of them.
Another example is a function that needs to follow a given signature for API
reasons (e.g. a callback that follows a given format) but doesn't use some of
its arguments; it's better to spell out in the argument what the API the
function implements is, instead of adding `_` variables.

```
local foo, bar = some_function() --luacheck: ignore 212/foo
print(bar)
```

* luacheck warning 542 (empty if branch) can also be ignored, when a sequence
of `if`/`elseif`/`else` blocks implements a "switch/case"-style list of cases,
and one of the cases is meant to mean "pass". For example:

```lua
if warning >= 600 and warning <= 699 then
   print("no whitespace warnings")
elseif warning == 542 then --luacheck: ignore 542
   -- pass
else
   print("got a warning: "..warning)
end
```

> **Rationale:** This avoids writing negated conditions in the final fallback
case, and it's easy to add another case to the construct without having to
edit the fallback.