esi-class
Base class for object oriented programming in lua This library shall be used for each library where object orientation makes sense.
Basic Concept
This library incorportes different concepts required for object oriented Programming, while still keeping memory foodprint and performance in mind.
Inheritance
Inheritance is currently limited to simple direct inheritance, there is currently no possibility to inherit from more than one class. Creating a new class is done by calling the "EXTEND" methode on a CLASS. This methods requires a name and may take a property template (the class declaration). But it is also possible to add class members after the definition of the class itself.
Example
-- create an new class, whith only class varaibles and default __INIT__ function
local ESI_CLASS = require("esi-class")
local myClass = ESI_CLASS:__EXTEND__("myClass", {
propertyA = "a", -- class varibale
propertyB = "b" -- class variable
})
function myClass:GET_A()
return self.propertyA
end
function myClass:GET_B()
return self.propertyB
end
local instance1 = myClass() -- create an instance
local instance2 = myClass() -- create an instance
local a1 = instance1:GET_A()
local a2 = instance2:GET_A()
local b1 = instance1:GET_B()
local b2 = instance2:GET_B()
local aClass = myClass:GET_A()
local bClass = myClass:GET_B()
return {aClass= aClass, bClass= bClass, a1=a1,a2=a2, b1=b1, b2=b2 }
Example
-- create an new class, whith it's own init funtion
local ESI_CLASS = require("esi-class")
local SUBTYPE = require("esi-subtype")
local TOOL = require("esi-tool")
local myClass = ESI_CLASS:__EXTEND__("myClass", {
__INIT__ = function(class, template)
-- copy constructor
if SUBTYPE.get(template) == class:__GET_CLASSNAME__() then
return TOOL:DEEPCOPY(template, 0)
else
-- regular constructor
-- declaration ( with default value )
local obj = {
a = "unknown",
b = "unknown"
}
-- initialization by template input.
obj.a= template.a or obj.a
obj.b= template.a or obj.b
return obj
end
end
})
function myClass:GET_A()
return self.a
end
function myClass:GET_B()
return self.b
end
local instance1 = myClass({a=1, b=2}) -- create an 1st instance
local instance2 = myClass({a=3, b=4}) -- create an 2nd instance
local instance3 = myClass(instance1) -- copy constructor
return { instance1, instance2, instance3 }
Objects
Object are created by calling the CLASS object. Internally this first calls the "INIT" methode and then the "SET_CLASS methode. As "SET_CLASS" should be suitable for most classe, only the "INIT" methode has to be defined for a new class. The name ase well as the behaviour are inspired by python, and should be used in a similar way. See: https://docs.python.org/3/tutorial/classes.html#a-first-look-at-classes
Object Hint
Don’t define function or any other lua object, which is not JSON serializable in the object which is returned by the INIT function. Functions shall always be defined as a property of the class ( either as input to the EXTEND method or defined later).
Underlying Architecture
The idea of this whole inheritance is, that each object is a LuaTable on it’s own rights. All class specific content like "className", "parent" and all functions on can call on this object are in the metatable. This is archived, by assigning the class of an object to the index entry. So the index of each object points to it’s class and thus allows to access everything which was defined on that class. But the class is a object on it’s own rights as well, which also has an metatable and also has an __index entry, but this points to the parent class.
Inheritance
That way inheritance is realised, by following the chain of __index calls automatically done by lua. In oder to create (inherit) a new class the EXTEND function must be called on the base class. As part of this extention, an INIT function should be defined for that class ( similar to python ), this function actually initializes the objects and defines all object specific data. The object defined in the INIT function should be JSON serializable (no functions). In additiona to the INIT function, a SET_CLASS function exists, but this is inherited from esi-class automatically and should not be touched. ( exceptions exist )
Object Instanciation
If an new object is instanciated, the INIT function of the class is called to create the LuaTable (content) which is not a "object" yet, and then the SET_CLASS function is called to initialize all metatable related entries, which form the "object" character. That happens automatically behind the scenes by the __call function. ( this was added to the metatable of the newly created class by the EXTEND() function )
Dependencies:
library | version | inmation core library |
---|---|---|
debug |
1.0.0 |
yes |
rapidjson |
0.6.0 |
yes |
esi-tool |
1.0.0 |
yes |
esi-subtype |
1.0.0 |
yes |
Available functions:
All functions have to be called according to the ESI standard, using colons, e.g. lib:FUNCTIONNAME(params)
Documentation
_LOG_ERROR
Description
Log error message
creates an error entry via syslib.log if logging is enabled by SET_LOG(true).
Parameters
Name | Description |
---|---|
topic |
the current scope / topic |
detail |
details for the log message |
traceOn |
if true or nil, enables the traceback in the error message. |
Examples
local esi_lib = require "esi-class"
local myClass = esi_lib:__EXTEND__("myClass")
local object = myClass()
object:SET_LOG(true)
object:_LOG_ERROR("Current Area", "Something went wrong ...") -- with traceback
object:_LOG_ERROR("Current Area", "Something went wrong ...", false) -- without traceback
_LOG_WARN
_LOG_INFO
_LOG_DEBUG
_ASSERT
Description
ASSERT
this is an local assert function, calls a assert if debugging was enabled via SET_DEBUG(true). due to limitations in lua, this does not work exactly like calling assert() in the code, but similar. here traceback is used to generate usefull information in the assert message. otherwise it only checks the assertion and creates an error entry if the assertion is false.