esi-class
Base class for object oriented programming in Lua
This library should be used for each library where object orientation makes sense.
Basic Concept
This library incorporates different concepts required for object oriented programming, while keeping memory footprint and performance in mind.
Inheritance
Inheritance is currently limited to simple direct inheritance. Currently there is no possibility to inherit from more than one class. Creating a new class is done by calling the "__EXTEND__" method 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 a new class, with only class variables 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 a new class, with its own init function
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__" method and then the "__SET_CLASS__" method. As "__SET_CLASS__" should be suitable for most classes, only the "__INIT__" method has to be defined for a new class. The name as well as the behavior 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 a 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 in its own right. All class specific content like "__className", "__parent" and all functions which can be called 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 its class and thus allows to access everything which was defined in that class. But the class is an object on its own right as well, which also has a metatable and also has an __index entry, but this points to the parent class.
Inheritance
That way inheritance is realized, 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 extension, 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 addition to the __INIT__ function, a __SET_CLASS__ function exists, but this is inherited from esi-class automatically and should not be touched. (exceptions exist) If a new object is instantiated, the __INIT__ function of the class is called to create the LuaTable (content) which is not an "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
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. |
Returns
returns nothing
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
CLASS:_ASSERT
Description
ASSERT
this is a local assert function, calls an 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 useful information in the assert message.
otherwise it only checks the assertion and creates an error entry if the assertion is false.
Parameters
| Name | Description |
|---|---|
condition |
value or condition which is evaluated |
error_message |
message shown if condition is false |