Refer to RFC 2119 to interpret MUST, SHOULD and MAY.
- Go code review comments
- The Olivine Labs style guide
- The Lua Modules Style series.
- The style of some reference Lua code bases, including the Lua standard library and LuaSocket.
Ternaries with litterals are OK:
local x = y and "yes" or "no"
Ternaries with a variable as the second element should be avoided. Remember:
1 and false or 2 -- do not do this, evaluates to 2
Modules MUST NOT set or access any global variable when required.
Modules MUST always return a table when required. If you would rather like
to return a function you MAY set the __call
metamethod on the table
instead.
Internal modules that can be used in different contexts MAY use the lima
namespace. Modules that are released as Open Source SHOULD NOT be namespaced.
When a module behaves like a class, it SHOULD expose a constructor called new
.
local dog = require "lima.example.dog"
local my_dog = dog.new()
A module SHOULD NOT have state. If a module needs configuration, turn it into a factory. For instance, this (from an Open Source module we did not write):
local mp = require "MessagePack"
mp.set_integer("unsigned")
should have this interface instead:
local messagepack = require "MessagePack"
local mp = messagepack.new({integer = "unsigned"})
Your code MUST pass luacheck. If it does
not with default settings, you must provide a .luacheckrc
with sensible
exceptions.
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, like the Lua io
library, LuaSocket
and luaposix do.
On errors such as API misuse, an error SHOULD be thrown, either with error()
or assert()
.
A different error handling convention MAY be used in parts of the code where it makes sense, for instance in FUSE code where FLU expects you to throw POSIX error codes.
You SHOULD verify the type and shape of arguments passed to public functions in your modules using assert. You MAY also do so for private functions. You MAY avoid those checks in functions that are intended to be very fast.
local function is_posint(x)
return (math.floor(x) == x) and (x >= 0)
end
local function foo(s, t)
assert(type(s) == "string")
t = t or {}
t.x = t.x or 42
assert(
type(t) == "table" and
is_posint(t.x)
)
end
Style homogeneity within a file trumps everything else, including all the rules below.
If you import open source code and modify it slightly, you MUST stick to the style of the original code. If you modify it a lot and do not intend to merge any upstream changes ever, you MAY convert the code to Lima style. You MUST do this in a separate commit which does not include any other modification. You SHOULD use "cosmetics" as the commit message.
Tests can be considered as a DSL, and as such are not required to follow this style guide strictly. It MAY make sense to have different rules in a DSL if they improve legibility.
All new code MUST be indented with four spaces.
Most operators SHOULD be surrounded with spaces. Commas MUST have no whitespace before them and some after them.
local x, y = 1, 2
You MUST NOT leave a space between the name of a function and the opening parenthesis of the arguments (despite the fact that the Lua manual does this).
You MUST leave a space between a function and its litteral string or table argument when called with no parentheses.
You SHOULD NOT use whitespace to align things vertically.
-- Do not do this.
local chunky = 4
local foo = 65
You SHOULD keep line length below 80 characters. When needed, you SHOULD indent tables and function arguments like this:
some_function(
argument_1,
argument_2,
a_very_long_argument,
other_arguments...
)
Alternatively, you MAY put several arguments on the same line, but you SHOULD always indent with four spaces and leave the closing parenthesis on its own line.
some_function(
argument_1, argument_2, a_very_long_argument,
other_arguments...
)
In Lua, function f(...)
is syntactic sugar for f = function(...)
and
local function f(...)
is syntactic sugar for local f; f = function(...)
.
You SHOULD use this sugar only in its second form, when declaring a new local function.
You MUST NOT use the sugar:
- to define global functions;
- to define functions in tables;
- to define a function whose local is already declared.
local g
local function f(...) end
g = function(...) end
local t = {
f = f,
h = function(...) end,
}
t.g = g
t.i = function(...) end
In Lua, x:f(...)
is syntactic sugar for x.f(x, ...)
.
You MUST NOT use the colon sugar for method definition.
local t = {n = 42}
t.f = function(self) print(self.n) end -- OK
function t:f() print(self.n) end -- not OK
You MUST use the sugar for method calls.
t:f() -- OK
t.f(t) -- not OK
Note that this is completely different from using this in a module:
local function f(self) ... end
local g = function(self)
f(self) -- and not self:f()
end
The above does not have the same meaning (it creates a closure, meaning that the
user cannot override the definition of f
as called in g
). This pattern is
perfectly OK. What would not be OK would be self.f(self)
.
Also, of course when using pcall
you don't have a choice:
pcall(self.f, self)
Remember: try to keep a homogeneous style within a single file or module.
You SHOULD NOT omit parenthesis for functions that take a unique string litteral
argument. An exception to this rule is require
, which you SHOULD use like
this.
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.
local a_module = require "a_module"
local an_instance = a_module.new {
a_parameter = 42,
another_parameter = "yay",
}
an_instance:a_function("a_string")
In general you SHOULD NOT use semicolons. In particular, the separator between table elements MUST always be a comma.
If you write a table on multiple lines, you SHOULD add a comma after the last element. If you write a table on a single line, you SHOULD NOT.
local t = {
x = 1,
y = 2,
}
local t = {x = 1, y = 2}
You SHOULD use short variable names (even single letters) for variables with limited scope and slightly longer variable names for functions parameters and for variables that may be used far from their declaration (but you SHOULD NOT have many such variables).
You SHOULD use short names for functions and methods intended to be used frequently and longer, more descriptive names for functions and methods that will be used more rarely.
In general, you SHOULD use snake_case for locals, functions, methods, table fields and module names. You SHOULD use UPPER_CASE for constants.
You SHOULD NOT use CamelCase and you MUST NOT use snakeCase.
You SHOULD NOT use anonymous functions if they span several lines.
You MAY do so if they fit on a single line.
local function my_handler(...)
--[[ do something long ]]
end
local t = {
handler_1 = my_handler,
handler_2 = function(...) end,
}
rpc_call("SOME_RPC", my_handler)
rpc_call("SOME_RPC", function(...) print("RPC called") end)
Two spaces and 80 chars max line length is a common lua standard. I totally disagree with the four spaces.