.profile/lua-style.md

201 lines
4.7 KiB
Markdown
Raw Normal View History

<!-- vim: set noexpandtab :miv -->
# Comments
1. Put no space after `--` for commented out code
2. Put one space after `--` for actual comments
Example:
--print("foo")
print(bar) -- Prints a bar
1. Use `-->` to signal output or return values
Example:
print(2 * 2) --> 4
return h * w --> area
1. Use [ldoc](syntax) to document functionality
Example:
--- Foos a Bar
function foo(bar)
1. Use `--` for comments that apply to the entire line
2. Use `--[[]]` for comments that apply to single elements of a line
Example:
local x, y -- coordinates
local h --[[height]], r --[[radius]]
1. Use `--[[]]` comments to comment out items from a list
2. Include separators in the comment (or not) according to the rules in the
table / sequence section
print("Hello", "World"--[[, "foo", "bar"]])
local elements = { foo, --[[bar,]] }
1. Prefer splitting lines to using several comments per line
Example:
local r -- radius
local h -- height
1. Always close multi-line comments with `--]]`
Example:
--[[
this code
does stuff
--]]
1. Always close inline ranged comments with `]]`
Example:
local foo --[[Foo]], bar --[[Bar]]
# Variables
1. Use `do ... end` blocks to limit the scope of a local variables
2. Put the `do` keyword on the same line as a related declaration
Example:
local foo do
local bar = 2 + 2
foo = bar * 2
end
# Tables
## Spacing
<!-- inner spaces -->
1. Either use one space after `{` and one before `}`
2. Or neither of them
3. Put spaces *after* the separator (if at all), never before
Example:
2019-07-18 07:24:37 +00:00
local outer = { {"inner",1}, {"inner",2}, }
<!-- multiline -->
1. Either put the entire table on one line
2. Or don't put any items on the same line as the curly braces.
3. Indent the items of the table
Example:
2019-07-18 07:24:37 +00:00
local oneline = {'hello', 'world',}
lcoal multiline = {
'hello',
'world',
}
## Sequence
<!-- comma for lists, semicolon for sets -->
1. Use commas (`,`) to separate order-dependant items (list)
2. Use semicolons (`;`) to separate order-independant items (set)
Example:
2019-07-18 07:24:37 +00:00
local ingredients = { "eggs"; "flour"; "milk"; }
local steps = { "mix", "fry", }
<!-- semantic last separator -->
1. Put a separator after the last element if more can logically follow
2. Put no separator after the last element if none should logically follow
3. Put no separator after the last element if external conditions must change
for an additional item to be inserted.
Example:
2019-07-18 07:24:37 +00:00
local color = { 0xff, 0x20, 0x40 }
local line = { {0, 0}, {0, 20}, {20, 20}, }
## Map
<!-- sequence first -->
1. Place key-value pairs after the sequence
2. Put a semantic separator after the last element as with pure sequences for
open-ended sequences
3. Or use a different separator to signal that no items should be added
Example:
2019-07-18 07:24:37 +00:00
local pancakes = {
'mix', 'fry';
ingredients = { 'milk'; 'eggs'; 'flour' };
}
local pancakes = {
'milk'; 'eggs'; 'flour',
steps = {'mix', 'fry'};
}
<!--
This last one looks a bit awkward, but the benefit of the added
semantic meaning may well outweigh it looking a bit weird at first.
-->
<!-- commas for logical order -->
1. Use commas if the elements follow some logical order
2. Use semicolons otherwise
3. Apply same rules as with sequnces for separator after last element
Example:
2019-07-18 07:24:37 +00:00
local point = {x=20, y=30}
local tasks = { monday = {'call steve'}, tuesday = {'fix kitchen door'}, }
local person = { name="John Doe"; age="Unknown" }
<!-- arbitrary integer keys -->
1. Treat arbitrary integer keys as string keys
2. Use square brackets for numbers acting as keys in a map
3. Judge based on semantic meaning, not on technicalities
Example:
2019-07-18 07:24:37 +00:00
local ages = { [20]="John, Henry"; [21]="William"; }
local errors = { [1]="File not Found"; [2]="Permission Denied" }
2019-07-18 09:02:26 +00:00
# Errors
1. On error, functions should return `nil` + error message
2. Whenever possible, an identifier should be passed as the third argument
Explanation:
`nil` + message is a widely used convention for returning errors in Lua.
However, error messages are not guaranteed to remain unchanged,
this they are poorly suited to identify an error programatically.
Thus it makes sense to pass a third value that can be used to identify an error
condition. This can be a numeric error code, a string or a unique table.
Example:
local function divide(dividend, divisor)
if divisor == 0 then
return nil, 'Attempting to divide by 0', 'division-by-0'
else
return dividend / divisor
end
end
1. Libraries should never raise errors to the calling code.
Explanation:
Because error-handling mechanisms in Lua are very simple
and there is no mechanism like 'rescue' blocks,
errors are hard to deal with in section of code that require cleanup operations
to keep state (be it internal or external) consistent.