Lua code snippets

-- 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

chaining constructors across derived classes

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

pitfalls, traps, quirks, flaws

PITFALL: 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
PITFALL: Write ~= instead of !=
!= does not exist in Lua.
However, hacking Lua to recognize != is very easy. llex() in llex.c:
< case '~': {
> case '~': case '!': {  /*--HACK--*/
PITFALL: Numeric for loop IS TOTALLY DIFFERENT FROM C/C++:
for i=1, i < 100, 10 do
         ^^^^^^^  WRONG!!  Evaluated only once.
PITFALL: Accessing table as array, but was created as map, vv:
key = "a"
t[key] = val    -- becomes MAP
...
for i=1, #t do  -- WRONG, isn't ARRAY (every index is string, not number)
FLAW: Statement consisting of function calls joined with logical 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

commentary/opinion

positive:
Lua has a simple syntax, yet is very expressive. Tables as the only data structure is innovative. Lua can be integrated with C++ programs, and fast enough to write some code in Lua instead. Lua itself is written in a small amount of C code.

negative:
Design of Lua has minor flaws (quirks, others may say) and underwent drastic changes during its early evolution that broke compatibility.