I'm having a hard time grokking classes in Lua. Fruitless googling led me to ideas about meta-tables, and implied that third-party libraries are necessary to simulate/write classes.
Here's a sample (just because I've noticed I get better answers when I provide sample code):
public class ElectronicDevice
{
protected bool _isOn;
public bool IsOn { get { return _isOn; } set { _isOn = value; } }
public void Reboot(){_isOn = false; ResetHardware();_isOn = true; }
}
public class Router : ElectronicDevice
{
}
public class Modem :ElectronicDevice
{
public void WarDialNeighborhood(string areaCode)
{
ElectronicDevice cisco = new Router();
cisco.Reboot();
Reboot();
if (_isOn)
StartDialing(areaCode);
}
}
Here is my first attempt to translate the above using the technique suggested by Javier.
I took the advice of RBerteig. However, invocations on derived classes still yield: "attempt to call method 'methodName' (a nil value)"
--Everything is a table
ElectronicDevice = {};
--Magic happens
mt = {__index=ElectronicDevice};
--This must be a constructor
function ElectronicDeviceFactory ()
-- Seems that the metatable holds the fields
return setmetatable ({isOn=true}, mt)
end
-- Simulate properties with get/set functions
function ElectronicDevice:getIsOn() return self.isOn end
function ElectronicDevice:setIsOn(value) self.isOn = value end
function ElectronicDevice:Reboot() self.isOn = false;
self:ResetHardware(); self.isOn = true; end
function ElectronicDevice:ResetHardware() print('resetting hardware...') end
Router = {};
mt_for_router = {__index=Router}
--Router inherits from ElectronicDevice
Router = setmetatable({},{__index=ElectronicDevice});
--Constructor for subclass, not sure if metatable is supposed to be different
function RouterFactory ()
return setmetatable ({},mt_for_router)
end
Modem ={};
mt_for_modem = {__index=Modem}
--Modem inherits from ElectronicDevice
Modem = setmetatable({},{__index=ElectronicDevice});
--Constructor for subclass, not sure if metatable is supposed to be different
function ModemFactory ()
return setmetatable ({},mt_for_modem)
end
function Modem:WarDialNeighborhood(areaCode)
cisco = RouterFactory();
--polymorphism
cisco.Reboot(); --Call reboot on a router
self.Reboot(); --Call reboot on a modem
if (self.isOn) then self:StartDialing(areaCode) end;
end
function Modem:StartDialing(areaCode)
print('now dialing all numbers in ' .. areaCode);
end
testDevice = ElectronicDeviceFactory();
print("The device is on? " .. (testDevice:getIsOn() and "yes" or "no") );
testDevice:Reboot(); --Ok
testRouter = RouterFactory();
testRouter:ResetHardware(); -- nil value
testModem = ModemFactory();
testModem:StartDialing('123'); -- nil value
Lua does not have the concept of class; each object defines its own behavior and has a shape of its own. Nevertheless, it is not difficult to emulate classes in Lua, following the lead from prototype-based languages, such as Self and NewtonScript. In those languages, objects have no classes.
OOP in LuaYou can implement object orientation in Lua with the help of tables and first class functions of Lua. By placing functions and related data into a table, an object is formed.
The __index metamethod in Lua Programming We can explicitly put in the __index method in a table and provide it the named values that we want it to return instead of nil.
Constructors are expressions that create and initialize tables. They are a distinctive feature of Lua and one of its most useful and versatile mechanisms. The simplest constructor is the empty constructor, {} , which creates an empty table; we saw it before.
Here's an example literal transcription of your code, with a helpful Class
library that could be moved to another file.
This is by no means a canonical implementation of Class
; feel free to define your object model however you like.
Class = {}
function Class:new(super)
local class, metatable, properties = {}, {}, {}
class.metatable = metatable
class.properties = properties
function metatable:__index(key)
local prop = properties[key]
if prop then
return prop.get(self)
elseif class[key] ~= nil then
return class[key]
elseif super then
return super.metatable.__index(self, key)
else
return nil
end
end
function metatable:__newindex(key, value)
local prop = properties[key]
if prop then
return prop.set(self, value)
elseif super then
return super.metatable.__newindex(self, key, value)
else
rawset(self, key, value)
end
end
function class:new(...)
local obj = setmetatable({}, self.metatable)
if obj.__new then
obj:__new(...)
end
return obj
end
return class
end
ElectronicDevice = Class:new()
function ElectronicDevice:__new()
self.isOn = false
end
ElectronicDevice.properties.isOn = {}
function ElectronicDevice.properties.isOn:get()
return self._isOn
end
function ElectronicDevice.properties.isOn:set(value)
self._isOn = value
end
function ElectronicDevice:Reboot()
self._isOn = false
self:ResetHardware()
self._isOn = true
end
Router = Class:new(ElectronicDevice)
Modem = Class:new(ElectronicDevice)
function Modem:WarDialNeighborhood(areaCode)
local cisco = Router:new()
cisco:Reboot()
self:Reboot()
if self._isOn then
self:StartDialing(areaCode)
end
end
If you were to stick to get/set methods for properties, you wouldn't need __index
and __newindex
functions, and could just have an __index
table. In that case, the easiest way to simulate inheritance is something like this:
BaseClass = {}
BaseClass.index = {}
BaseClass.metatable = {__index = BaseClass.index}
DerivedClass = {}
DerivedClass.index = setmetatable({}, {__index = BaseClass.index})
DerivedClass.metatable = {__index = DerivedClass.index}
In other words, the derived class's __index
table "inherits" the base class's __index
table. This works because Lua, when delegating to an __index
table, effectively repeats the lookup on it, so the __index
table's metamethods are invoked.
Also, be wary about calling obj.Method(...)
vs obj:Method(...)
. obj:Method(...)
is syntactic sugar for obj.Method(obj, ...)
, and mixing up the two calls can produce unusual errors.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With