Lua Language

20 August 2019 Link



Here are some notes that have been useful for me. Also refer to this nice brief Introduction to Lua on the wxLua website

Tables

    • Often you want to find everything in a table. There are two main ways of doing this. The simplest is to use table.foreach, like this:
t = {
  name = "nick",
  class = "mage",
  hp = 234,
  online = true
}

table.foreach (t, print)

Output

online true
name nick
class mage
hp 234

The other main way of iterating through a table is to use the "for ... pairs" construct, like this:
t = {
  name = "nick",
  class = "mage",
  hp = 234,
  online = true
}

for k, v in pairs (t) do
  print (k, v)
end -- for loop

Output

online true
name nick
class mage
hp 234



NOTE: Variables only hold references to tables i.e. they are all pointers to the actual data, once all the references to a data are gone the data is garbage collected so any time you do operations on the variable its the pointed data that is being modified

Functions

Pass By Value or Pass By Reference?


From here
You guessed right, table variables are passed by reference. Citing Lua 5.1 Reference Manual:

There are eight basic types in Lua: nil, boolean, number, string, function, userdata, thread, and table. ....

Tables, functions, threads, and (full) userdata values are objects: variables do not actually contain these values, only references to them. Assignment, parameter passing, and function returns always manipulate references to such values; these operations do not imply any kind of copy.

So nil, booleans, numbers and strings are passed by value. This exactly explains the behavior you observe.

Pre-Defined functions

require

  • A module is a library that can be loaded through require and that defines one single global name containing a table.
  • package.path variable has the paths that the require function searches for the lua module. Every path is separated by a semi-colon and if there is any question mark in the path then that is replaced by the module name.
  • if nothing is found from package.path then lua searches from package.cpath assuming the module is a C library to be linked.
  • Well-behaved C libraries should export one function called luaopen_modname, which is the function that require tries to call after linking the library.
  • if a module is named a-b, require expects its open function to be named luaopen_b, instead of luaopen_a-b (which would not be a valid C name anyway). So, if we need to use two modules named mod, we can rename one of them to v1-mod (or -mod, or anything like that). When we call m1=require"v1-mod", require will find both the renamed file v1-mod and, inside this file, the function with the original name luaopen_mod. This allows maintaining multiple versions of C libraries and load them simultaneously.

Object Oriented Programming in Lua


Public and Private


Everything private would have to be an upvalue

To create a class with public and private methods create a class creating function and define all methods and variables inside the class. When returning the object filled up with those defined functions and variables just don't include the variables and functions you want to be private since now they become upvalues of the functions and can only be accessed by them. Example from Programming in Lua:

function newAccount (initialBalance)
    local self = {balance = initialBalance}
    local withdraw = function (v)
        self.balance = self.balance - v
    end
    local deposit = function (v)
        self.balance = self.balance + v
    end
    local getBalance = function () return self.balance end
    return {
         withdraw = withdraw,
         deposit = deposit,
         getBalance = getBalance
    }
end

General Structure


do
   local var  ----- private static
   local var4
   var1 ----------global
   new = function( )    --- Consructor
      local var2   ---------private
      local var3   ---------made public by object return below
      return {var3 = var3}
   end
end
Important things to note:
  1. Private static things cannot see private variables or functions
  2. To be able to see a private static thing either by new or another private static thing like var4 it must be defined before, i.e. if var is a function var cannot see var4, but var4 can see var just fine since it was defined before. The way to get around is by declaring a reference first as follows:
do
	local func2_ref
	local function func1(x)
		if x then
			return func2_ref(false)
		else
			return 1
		end
	end

	local function func2(x)
		if x then
			return func1(false)
		else
			return 10
		end
	end
	func2_ref = func2

	function newObj()
		return {func1 = func1, func2 = func2}
	end
end

Protected Variables

The above structure returns a object. To derive and inherit the object we will have to define a __index metamethod or if everything in the object is to be exposed to the derived object then just the object can be set in the __index value. The __index metamethod will define protected variables

do
   local var  ----- private static
   var1 ----------global
   new = function( )    --- Consructor
      local var2   ---------private
      local var3   ---------made public by object return below
      local var4   ---------protected
      local o = {var3 = var3}
      o.__index = function(tab,key)
         if key = "var4" then    -- check for protected variables here
            return nil
         else
            return o[key]
         end
      end
      return o
   end
end

Inheritance

If every object as defined above is used then inheritance and multiple inheritance works easily:
-- Let o1 be an object derived from definition with the above structure
newObj = {}
setmetatable(newObj,o1)


Multiple Inheritance

-- Let o1 and o2 be 2 different objects derived from definitions with the above structure
newObj = {parents={o1,o2}}
newObj.__index = function(tab,key)   -- access handling method for multiple inheritance
   for i = 1,#newObj.parents do
      if newObj.parents[i][key] then
         return newObj.parents[i][key]
      end
   end
end

Programming tricks

  1. To find out all undeclared variables i.e. variables going into Global space do:
    luac -p -l myprogram.lua >> bytecode.txt
    and then search bytecode.txt for SETGLOBAL to find all global variables.

Deployment of software

  1. Used my custom script many2one.lua to combine all lua files (linked by require) into one main file. (All it does it defines an alternate require function that uses loadstring instead of loadfile and includes all the files as strings in the beginning of the main file)
  2. Used wxluafreeze to convert it to an exe using the command:
     lua wxluafreeze.lua wxluafreeze.exe KarmApp.lua Karm.exe


Lua Notes

  1. Lua C API
  2. Lua Notes
  3. Lua Compiler

Lua References

  1. Detecting undefined Variable

Lua Tools

  1. LuaXML