quirks can (and will) come around when migrate from one language to another, as languages often have different interpretations and implementations; it would be helpful if prominent inconsistencies are logged to avoid going over the getting started chapters again and again; this article is a list of pitfalls for people migrating to lua (from an unknown whatever language); in spite of word “pitfall” in title, this article does not mean to be a verdict about better or worse, but just poses the differences as they are;

here the lua reference in use is Programming in Lua (first edition) that aims at lua 5.0; these days most people would be on lua 5.4, but we are getting started, right? for those who want the latest language reference visit the page Lua 5.4 Reference Manual;

code examples below are in lua 5.4; so the code may not entirely conform to the lua reference in use;

each item has a series of ref tags that can be followed to find authentic information:

1. (ref) a chunk can be a single line in interactive mode;

2. (ref) global variables do not need to be declared or deleted; they can be assigned, and they are existent iff non-nil;

3. (ref) lua is case-sensitive;

4. (ref) lua has 8 basic types: nil, boolean, number, string, userdata, function, thread, and table;

5. (ref) nil is different from anything but nil:

> print(nil == nil)
true
> print(nil == false)
false
> print(nil == 0)
false
> print(nil == '')
false
> print(nil == {})
false

6. (ref) false and nil are false, everything else is true; zero 0 is true; empty string '' is true;

7. (ref) lua numbers are all (double) floats; lua has no integer type, because lua floats have no rounding error upto 100,000,000,000,000;

8. (ref) strings are immutable;

9. (ref) single-quoted and double-quoted literal strings are the same;

10. (ref) lua has automatic conversions between numbers and strings:

> print(type("12" + 34), "12" + 34)
number  46
> print(type("12" .. 34), "12" .. 34)
string  1234

11. (ref) use tonumber and tostring for manual conversions between numbers and strings;

12. (ref) lua table is associative array (aka: dict, map);

13. (ref) all types except nil can be used as table key (aka: index); and key types can be mixed;

14. (ref) table values evaluate to nil if not initialized;

15. (ref) use table with integer keys to implement conventional array;

16. (ref) use ipairs to iterate conventional array;

17. (ref) lua supports functional programming; functions are first-class citizens;

18. (ref) relational operators always result in true or false;

19. (ref) lua inequality operator is ~= (not !=);

20. (ref) values of different types are not equal:

> print(0 == '0')
false
> print(0 == '')
false
> print(0 == {})
false
> print(0 == false)
false
> print(0 == nil)
false

21. (ref) lua compares tables, userdata, and functions by reference:

> a = {}
> b = {}
> c = a
> a == b
false
> a == c
true

22. (ref) logical operators are and, or, not;

23. (ref) logical operators consider false and nil as false and anything else as true;

24. (ref) both and and or use shortcut evaluation;

25. (ref) lua lacks ternary operator: a and b or c is bug;

26. (ref) operator not always returns true or false:

> print(not nil)
true
> print(not false)
true
> print(not 0)
false
> print(not '')
false
> print(not {})
false

27. (ref) one can use (not not ...) to convert any value to boolean;

28. (ref) operator not has higher precedence than relational operators (eg: ==):

> print(not not 0 == 0)
false
> print((not not 0) == 0)
false
> print(not not (0 == 0))
true

29. (ref) table constructor can mix explicit and implicit indexes:

> x = {'a', 'b', [8]='c', 'd', 'e'}
> x[1]
a
> x[2]
b
> x[3]
d
> x[4]
e
> x[8]
c

30. (ref) mixing explicit and implicit indexes in table constructor can cause trouble:

> x = {'a', 'b', [2]='c', 'd', 'e'}
> x[1]
a
> x[2]
b
> x[3]
d
> x[4]
e
> x[2]
b

31. (ref) in multiple assignment, values are evaluated then assigned; so swap works:

> x, y = 3, 8
> x, y = y, x
> print(x, y)
8       3
> a = {4, 9}
> a[1], a[2] = a[2], a[1]
> print(a[1], a[2])
9       4

32. (ref) in multiple assignment, values are adjusted to variables; extra variables are assigned nil; extra values are discarded;

33. (ref) local variables are created with keyword local;

34. (ref) local variables have block scope; the scope begins after the declaration and goes to end of block;

local x = 1
for i = 1, 2 do
print(x)
local x = i * 2
print(x)
end

1
2
1
4

35. (ref) local variable declaration with assignment has same rule: extra variables are assigned nil; extra values are discarded;

36. (ref) local variable declaration without assignment initializes all variables with nil;

37. (ref) one can create an explicit block with do-end:

38. (ref) condition expression in if, while, etc. may be any value: false and nil are treated as false, others true;

39. (ref) numeric for: all three expressions are evaluated only once;

40. (ref) numeric for: loop variables are local variables visible only inside the loop;

41. (ref) numeric for: never change the value of loop variables;

42. (ref) generic for: loop variables are local variables visible only inside the loop;

43. (ref) generic for: never change the value of loop variables;

44. (ref) generic for: use ipairs to traverse conventional arrays; use pairs to traverse associative arrays;

45. (ref) there is an implicit return at the end of any function that returns nothing;

46. (ref) one can use colon : for object-oriented calls (aka: methods): o:foo(x) is the same as o.foo(o, x);

47. (ref) function parameters work like local variables, initialized with function arguments;

48. (ref) extra function parameters are assigned nil; extra function arguments are discarded;

49. (ref) lua lacks default arguments;

50. (ref) functions can return multiple results; the number of results depend on the circumstances of the call;

51. (ref) a function call used as an expression gives only the first result;

52. (ref) a function call gives all results only when it is the last expression in a list of expressions;

53. (ref) function results are appended with nil as needed;

54. (ref) table constructor collects all results from a call, without any adjustments;

55. (ref) one can force a call to return exactly one result using an extra pair of parentheses:

56. (ref) return f() returns all values returned by f;

57. (ref) return (f()) returns one single value;

58. (ref) unpack takes an array and returns all its elements as results (starting from 1);

59. (ref) three dots ... parameter collects a variable number of arguments into hidden table arg;

60. (ref) a function can have some fixed parameters plus a variable number of parameters;

61. (ref) lua lacks named arguments; simulate that by passing a table argument;

62. (ref) functions are anonymous:

function f (x) return x+1 end   --same
f = function (x) return x+1 end --same

63. (ref) local function syntactic sugar handles recursive functions, but not indirect recursive functions;