-- Mnemonic to avoid confusing pairs()/ipairs(). KEYS = pairs KEYS_VALS = pairs -- Looping: iterate over all keys/values of table t. for k, v in KEYS_VALS(t) do -- Looping: print all keys of table. for k in KEYS(t) do -- Looping: iterate by ordinals of table. for i=1, #t do -- Separating/splitting words of string. function SplitFields( str, sep ) if str[string.len(str)] ~= sep then local str2 = string.format( "%s%s", str, sep ) return {str2:match((str2:gsub("[^"..sep.."]*"..sep, "([^"..sep.."]*)"..sep)))} else return {str:match((str:gsub("[^"..sep.."]*"..sep, "([^"..sep.."]*)"..sep)))} end end fields = SplitFields( str, "," ) for key, word in KEYS_VALS(fields) do print( word ) end
Example of building class hierarchy in Lua. Unlike C++, chaining constructor functions must be written explictly.
-- Produces metatable (class table) that inherits methods from another one. function lib.DerivesFrom( BaseMT, t ) local t = t or {} setmetatable( t, BaseMT ) BaseMT.__index = BaseMT return t end -- Produces "instance table" from "class table" (metatable). -- For use in Class:new() method. function lib.NewInstance( classTable, argTable ) -- Construct instance table. local instance = argTable or {} setmetatable( instance, classTable ) classTable.__index = classTable return instance end Base = { } -- only root base class can begin with empty table -- ctor. function Base:new( name ) -- If base class is being instantiated, base class will be passed as self. -- Or, derivative is being instantiated, which chains ctors by passing its instance as self. if self == Base then self = lib.NewInstance( Base ) -- not chained, need new instance end self.name = name return self end -- lib.DerivedClass() produces "class table" that inherits from another "class table". -- Derived becomes metatable, inheriting from Base, from which instance tables can be produced. Derived = lib.DerivesFrom( Base ) function Derived:new( name, value ) -- Make instance table from derived metatable. if self == Derived then self = lib.NewInstance( Derived ) end Base.new( self, name ) -- chain to parent's ctor self.value = value -- derivative-specific return self end
if EXPR
will evaluate 0
/zero or empty string as TRUE -- not false!
Lua defines if EXPR
as true unless EXPR evaluates as false
or nil
(both are keywords).
Any defined/existing non-nil object is true -- even if its value is zero or empty string.
n = 0; if n then print( "true" ) end -- SURPRISE! Prints "true"! s = ""; if s then print( "true" ) end -- SURPRISE! Prints "true"!
Think of if
as meaning IfTrueOrDefined in Lua.
In these cases, should write explicit comparison operators:
n = 0; if n ~= 0 then print( "true" ) end -- correct/ok
~=
instead of !=
!=
does not exist in Lua.!=
is very easy. llex() in llex.c:
< case '~': { > case '~': case '!': { /*--HACK--*/
for
loop IS TOTALLY DIFFERENT FROM C/C++:
for i=1, i < 100, 10 do ^^^^^^^ WRONG!! Evaluated only once.
key = "a" t[key] = val -- becomes MAP ... for i=1, #t do -- WRONG, isn't ARRAY (every index is string, not number)
and/or
ought to be valid syntax:
This is a design flaw, despite this behavior being documented in reference manual (Lua-5.3 2021/08):
3.4 Expressions
If a function call is used as a statement (see 3.3.6), then its return list
is adjusted to zero elements, thus discarding all returned values.
Func1() or Func2() -- WRONG, causes syntax error local quirk = Func1() or Func2() -- ok if not Func1() then Func2() end -- ok, proper
Lua has a simple syntax, yet is very expressive. Tables as the only data structure is innovative. Lua can be integrated with C/C++ programs, and fast enough to write some code in Lua instead. Lua itself is written in a small amount of C code.
Design of Lua has minor flaws (quirks, others may say) and underwent radical changes during its early evolution that broke compatibility.