Difference between revisions of "Lua code style guidelines"

From Minetest Developer Wiki
Jump to navigation Jump to search
(Styling, wording fixes.)
Line 1: Line 1:
<span style="color: red;">This document is a draft and is still open for changes. Please post comments on the [[Talk:Lua_code_style_guidelines|talk]] page.</span>
+
<span style="color: #b64;">'''This document is a draft''' and is still open for changes. Please post comments on the [[Talk:Lua_code_style_guidelines|talk]] page.</span>
  
 
These are only guidelines for more readable code, in some (rare) cases they may result in less readable code and should not be followed.
 
These are only guidelines for more readable code, in some (rare) cases they may result in less readable code and should not be followed.
Line 6: Line 6:
  
 
* Write comments to describe why something is done, or why it is done in a particular way. Don't write comments that describe things that are obvious from the code.
 
* Write comments to describe why something is done, or why it is done in a particular way. Don't write comments that describe things that are obvious from the code.
  Good: <source lang="lua">width = width - 2  -- Adjust for 1px border on each side</source>
+
  <span style="color: #282;">Good:</span> <source lang="lua">width = width - 2  -- Adjust for 1px border on each side</source>
  Bad: <source lang="lua">width = width - 2  -- Decrement width by two</source>
+
  <span style="color: #b44;">Bad:</span> <source lang="lua">width = width - 2  -- Decrement width by two</source>
  
* Comments should follow English grammar rules, this means starting with a capital letter, using commas and apostrophes where appropriate, and ending with a period. The period may be omitted in single-sentence comments. If the first word of a comment is an identifier it's casing should not be changed.
+
* Comments should follow English grammar rules, this means '''starting with a capital letter''', using commas and apostrophes where appropriate, and '''ending with a period'''. The period may be omitted in single-sentence comments. If the first word of a comment is an identifier, its casing should not be changed. '''Check the spelling.'''
 
<source lang="lua">
 
<source lang="lua">
 
-- This is a properly formatted comment.
 
-- This is a properly formatted comment.
-- This isnt.              (Missing apostrophe)
+
-- This isnt.              (missing apostrophe)
-- neither is this.        (Lowercase first letter)
+
-- neither is this.        (lowercase first letter)
 
</source>
 
</source>
  
Line 19: Line 19:
 
<source lang="lua">
 
<source lang="lua">
 
--This is wrong.
 
--This is wrong.
 +
-- This is right.
 
</source>
 
</source>
  
 
* Inline comments should be separated from the code by two spaces.
 
* Inline comments should be separated from the code by two spaces.
 
<source lang="lua">
 
<source lang="lua">
foo()  -- A proper comment
+
foo()  -- A proper comment.
 
</source>
 
</source>
  
Line 31: Line 32:
  
 
* Indentation is done with one tab per indentation level.
 
* Indentation is done with one tab per indentation level.
 
+
* '''Lines are wrapped at 80 characters where possible''', with an upper limit of 90.
* Lines are wrapped at 80 characters where possible, with an upper limit of 90.
 
  
  
Line 73: Line 73:
  
 
* Use a single empty line to separate sections of long functions.
 
* Use a single empty line to separate sections of long functions.
 
 
* Use two empty lines to separate top-level functions and large tables.
 
* Use two empty lines to separate top-level functions and large tables.
 
 
* Do not use a empty line after conditional, looping, or function opening statements.
 
* Do not use a empty line after conditional, looping, or function opening statements.
Good:
+
<span style="color: #282;">Good:</span>
 
<source lang="lua">
 
<source lang="lua">
 
function foo()
 
function foo()
Line 85: Line 83:
 
end
 
end
 
</source>
 
</source>
Bad:
+
<span style="color: #b44;">Bad:</span>
 
<source lang="lua">
 
<source lang="lua">
 
function foo()
 
function foo()
Line 101: Line 99:
  
 
* Spaces are not used around parenthesis, brackets, or curly braces.
 
* Spaces are not used around parenthesis, brackets, or curly braces.
Good:
+
<span style="color: #282;">Good:</span>
 
<source lang="lua">
 
<source lang="lua">
 
foo({baz=true})
 
foo({baz=true})
 
bar[1] = "Hello world"
 
bar[1] = "Hello world"
 
</source>
 
</source>
Bad:
+
<span style="color: #b44;">Bad:</span>
 
<source lang="lua">
 
<source lang="lua">
 
foo ( { baz=true } )
 
foo ( { baz=true } )
Line 113: Line 111:
  
 
* Spaces are used after, but not before, commas and semicolons.
 
* Spaces are used after, but not before, commas and semicolons.
Good: <source lang="lua">foo(a, b, {c, d})</source>
+
<span style="color: #282;">Good:</span> <source lang="lua">foo(a, b, {c, d})</source>
Bad: <source lang="lua">foo(a,b,{c , d})</source>
+
<span style="color: #b44;">Bad:</span> <source lang="lua">foo(a,b,{c , d})</source>
  
* Spaces are used around binary operators. With the exception of the member access operator (".") where there shouldn't be spaces, and the concatenation operator ("..") where spaces are optional. In short one-line table definitions the spaces around the equals sign can be omitted.
+
* '''Spaces are used around binary operators.''' With the exception of the member access operator (".") where there shouldn't be spaces, and the concatenation operator ("..") where spaces are optional. In short one-line table definitions the spaces around the equals sign can be omitted.
  
Good:
+
<span style="color: #282;">Good:</span>
 
<source lang="lua">
 
<source lang="lua">
 
local num = 2 * (3 / 4)
 
local num = 2 * (3 / 4)
Line 128: Line 126:
 
}
 
}
 
</source>
 
</source>
Bad:
+
<span style="color: #b44;">Bad:</span>
 
<source lang="lua">
 
<source lang="lua">
 
local num=2*(3/4)
 
local num=2*(3/4)
Line 138: Line 136:
  
 
* Use spaces to align related things, but don't go overboard:
 
* Use spaces to align related things, but don't go overboard:
Good:
+
<span style="color: #282;">Good:</span>
 
<source lang="lua">
 
<source lang="lua">
 
local node_up  = minetest.get_node(pos_up)
 
local node_up  = minetest.get_node(pos_up)
 
local node_down = minetest.get_node(pos_down)
 
local node_down = minetest.get_node(pos_down)
 
</source>
 
</source>
Bad:
+
<span style="color: #b44;">Bad:</span>
 
<source lang="lua">
 
<source lang="lua">
 
local x                      = true
 
local x                      = true
Line 154: Line 152:
 
=== Tables ===
 
=== Tables ===
  
* Small tables may be placed on one line. Large tables have one entry per line, with the opening and closing braces on lines without items. In large tables the final element has a trailing comma.
+
* '''Small tables may be placed on one line.''' Large tables have one entry per line, with the opening and closing braces on lines without items. In large tables, the final element has a trailing comma.
Good:
+
<span style="color: #282;">Good:</span>
 
<source lang="lua">
 
<source lang="lua">
 
local foo = {bar=true}
 
local foo = {bar=true}
Line 164: Line 162:
 
}
 
}
 
</source>
 
</source>
Bad:
+
<span style="color: #b44;">Bad:</span>
 
<source lang="lua">
 
<source lang="lua">
 
foo = {bar = 0,
 
foo = {bar = 0,
Line 185: Line 183:
 
== Naming ==
 
== Naming ==
  
* Functions and variables should be named in <code>lowercase_underscore_style</code>. The exception is class-like functions, eg <code>PseudoRandom()</code>, which use UpperCamelCase.
+
* '''Functions and variables should be named in <code>lowercase_underscore_style</code>. The exception is class-like functions, eg <code>PseudoRandom()</code>, which use UpperCamelCase.'''
 
+
* Avoid inventing compound words; filename is okay, but getbox and collisiondetection are not.
* Avoid inventing compound words; filename is O.K., but getbox and collisiondetection are not.
+
* Avoid leading and/or trailing underscores. They're ugly and can be hard to see.
 
 
* Avoid leading and/or trailing underscores. They're ugly and can be hard to see.
 
  
  
Line 198: Line 194:
  
 
* You can put conditionals/loops with small conditions and bodies on one line, although this is discouraged for all but the smallest ones.
 
* You can put conditionals/loops with small conditions and bodies on one line, although this is discouraged for all but the smallest ones.
Good:
+
<span style="color: #282;">Good:</span>
 
<source lang="lua">
 
<source lang="lua">
 
local f, err = io.open(filename, "r")
 
local f, err = io.open(filename, "r")
Line 208: Line 204:
 
end
 
end
 
</source>
 
</source>
Bad:
+
<span style="color: #b44;">Bad:</span>
 
<source lang="lua">
 
<source lang="lua">
 
if not f and use_error then error(err) elseif not f then return err end
 
if not f and use_error then error(err) elseif not f then return err end
Line 214: Line 210:
  
 
* Don't compare values explicitly to true, false, or nil, unless it's really needed.
 
* Don't compare values explicitly to true, false, or nil, unless it's really needed.
Good:
+
<span style="color: #282;">Good:</span>
 
<source lang="lua">
 
<source lang="lua">
 
local f, err = io.open(filename, "r")
 
local f, err = io.open(filename, "r")
Line 226: Line 222:
 
end
 
end
 
</source>
 
</source>
Bad:
+
<span style="color: #b44;">Bad:</span>
 
<source lang="lua">
 
<source lang="lua">
 
if f == nil then return err end
 
if f == nil then return err end
Line 232: Line 228:
  
 
* Don't use unnecessary parenthesis unless they improve readability a lot.
 
* Don't use unnecessary parenthesis unless they improve readability a lot.
 
 
<source lang="lua">
 
<source lang="lua">
 
if y then bar() end -- Good
 
if y then bar() end -- Good
Line 239: Line 234:
  
 
* Write function definitions of the form <code>function foo()</code> instead of the lambda form <code>foo = function()</code>, except when putting functions in tables, where the second should be used.
 
* Write function definitions of the form <code>function foo()</code> instead of the lambda form <code>foo = function()</code>, except when putting functions in tables, where the second should be used.
 
+
* '''Avoid globals.''' The only globals that you should create are namespace tables.
* Avoid globals. The only globals that you should create are namespace tables.
+
* Don't let functions get too large. Maximum length depends on complexity; simple functions can be longer than complex functions.
 
 
* Don't let functions get too large. Maximum length depends on complexity; simple functions can be longer than complex functions.
 
 
 
 
* Avoid using Lua 5.2/LuaJIT-specific features unless you really need them.
 
* Avoid using Lua 5.2/LuaJIT-specific features unless you really need them.

Revision as of 16:47, 18 October 2014

This document is a draft and is still open for changes. Please post comments on the talk page.

These are only guidelines for more readable code, in some (rare) cases they may result in less readable code and should not be followed.

Comments

  • Write comments to describe why something is done, or why it is done in a particular way. Don't write comments that describe things that are obvious from the code.

Good:

width = width - 2  -- Adjust for 1px border on each side

Bad:

width = width - 2  -- Decrement width by two
  • Comments should follow English grammar rules, this means starting with a capital letter, using commas and apostrophes where appropriate, and ending with a period. The period may be omitted in single-sentence comments. If the first word of a comment is an identifier, its casing should not be changed. Check the spelling.
-- This is a properly formatted comment.
-- This isnt.              (missing apostrophe)
-- neither is this.        (lowercase first letter)
  • Comments should have a space between the comment characters and the first word.
--This is wrong.
-- This is right.
  • Inline comments should be separated from the code by two spaces.
foo()  -- A proper comment.
  • If you write comments for a documentation generation tool, write the comments in LuaDoc format.

Lines, spaces, and indentation

  • Indentation is done with one tab per indentation level.
  • Lines are wrapped at 80 characters where possible, with an upper limit of 90.


Continuation lines

  • Conditionals have following lines indented by two tabs:
if long_function_call(with, many, arguments) and
		another_function_call() then
	do_something()
end
  • Function arguments are indented by two tabs:
foo(bar, biz, "This is a long string..."
		baz, qux, "Lua")
  • Function definition continuations are also indented by two tabs.
function foo(a, b, c, d,
		e, f, g, h)
	...
end
  • When breaking around a binary operator you should break after the operator.
foo["bar"]["biz"]["baz"] = 
	"Example"
if a or b or c or d or
		e or f then
	foo()
end


Empty lines

  • Use a single empty line to separate sections of long functions.
  • Use two empty lines to separate top-level functions and large tables.
  • Do not use a empty line after conditional, looping, or function opening statements.

Good:

function foo()
	if x then
		bar()
	end
end

Bad:

function foo()

	if x then

		bar()
	end
end
  • Don't leave white-space at the end of lines.

Spaces

  • Spaces are not used around parenthesis, brackets, or curly braces.

Good:

foo({baz=true})
bar[1] = "Hello world"

Bad:

foo ( { baz=true } )
bar [ 1 ]
  • Spaces are used after, but not before, commas and semicolons.

Good:

foo(a, b, {c, d})

Bad:

foo(a,b,{c , d})
  • Spaces are used around binary operators. With the exception of the member access operator (".") where there shouldn't be spaces, and the concatenation operator ("..") where spaces are optional. In short one-line table definitions the spaces around the equals sign can be omitted.

Good:

local num = 2 * (3 / 4)
foo({bar=true})
foo({bar = true})
local def = {
	foo = true,
	bar = false,
}

Bad:

local num=2*(3/4)
local def={
	foo=true,
	bar=false,
}
  • Use spaces to align related things, but don't go overboard:

Good:

local node_up   = minetest.get_node(pos_up)
local node_down = minetest.get_node(pos_down)

Bad:

local x                       = true
local very_long_variable_name = false

local foobar    = true
local unrelated = {}

Tables

  • Small tables may be placed on one line. Large tables have one entry per line, with the opening and closing braces on lines without items. In large tables, the final element has a trailing comma.

Good:

local foo = {bar=true}
foo = {
	bar = 0,
	biz = 1,
	baz = 2,
}

Bad:

foo = {bar = 0,
	biz = 1,
	baz = 2}
foo = {
	bar = 0, biz = 1,
	baz = 2
}
  • In list-style tables where each element is short multiple elements may be placed on each line.
local first_eight_letters = {
	"a", "b", "c", "d",
	"e", "f", "g", "h",
}

Naming

  • Functions and variables should be named in lowercase_underscore_style. The exception is class-like functions, eg PseudoRandom(), which use UpperCamelCase.
  • Avoid inventing compound words; filename is okay, but getbox and collisiondetection are not.
  • Avoid leading and/or trailing underscores. They're ugly and can be hard to see.


Misc

  • Multiple statements on the same line are discouraged.

Bad:

foo(); bar()
  • You can put conditionals/loops with small conditions and bodies on one line, although this is discouraged for all but the smallest ones.

Good:

local f, err = io.open(filename, "r")
if not f then return err end

if     a then return a
elseif b then return b
elseif c then return c
end

Bad:

if not f and use_error then error(err) elseif not f then return err end
  • Don't compare values explicitly to true, false, or nil, unless it's really needed.

Good:

local f, err = io.open(filename, "r")
if not f then return err end

local t = {"a", true, false}
for i = 1, 5 do
	if t[i] == nil then  -- Needs an explicit nil check to avoid triggering on false.
		t[i] = "Default"
	end
end

Bad:

if f == nil then return err end
  • Don't use unnecessary parenthesis unless they improve readability a lot.
if y then bar() end -- Good
if (not x) then foo() end -- Bad
  • Write function definitions of the form function foo() instead of the lambda form foo = function(), except when putting functions in tables, where the second should be used.
  • Avoid globals. The only globals that you should create are namespace tables.
  • Don't let functions get too large. Maximum length depends on complexity; simple functions can be longer than complex functions.
  • Avoid using Lua 5.2/LuaJIT-specific features unless you really need them.