Classes in Lua, how does it work - lua

I'm new to Lua, and I'm trying to understand its OO part, for example :
lkw = {}
lkw.la= 0
function lkw:func(ge)
self.la = self.la + ge
end
function lkw:new()
local res = {}
setmetatable(res, self)
self.__index = self
return res
end
mylkw = lkw:new()
in this example the "class" lkw can create object using new, but what do self and index mean ?
should consider self as this in java/C++ and what is the index ?

This style of OOP is frequent in Lua. I do not like it because it is not explicit enough for me, but let me try to explain.
There are two confusing things: the use of the : sugar in function definitions and the use of the "class" as the metatable for its instances.
First, function a:b(...) is the same as a.b = function(self, ...), so let us remove all sugar:
lkw = {}
lkw.la = 0
lkw.func = function(self, ge)
self.la = self.la + ge
end
lkw.new = function(self)
local res = {}
setmetatable(res, self)
self.__index = self
return res
end
mylkw = lkw.new(lkw)
Now, this is "prototypal inheritance". lkw is the "prototype" for instances like mylkw. This is similar but slightly different from a "class".
When the new constructor is called, lkw is passed as the self argument.
The second and third lines of the constructor are weird. This is probably easier to understand:
lkw.new = function(self)
local res = {}
setmetatable(res, {__index = lkw})
return res
end
i.e.: if we do not find something in the instance we go look for it inside the prototype.
This explains how func works. The first time it is called, the instance will not contain a la key so lkw.la will be used.
The reason the code is not written this way is that the weird construction allows "prototypal inheritance": you could call "new" on mylkw and get an "instance of the instance" (i.e. in prototypal inheritance an instance and a child class are the same thing).
I think this is a very confusing feature. For reference this is about how I would write code that does about the same thing, with no inheritance:
local methods = {
func = function(self, ge)
self.la = self.la + ge
end
}
local lkw = {
new = function()
return setmetatable({la = 0}, {__index = methods})
end
}
local mylkw = lkw.new()

Related

Table not working as attribute in my class

I have a situation like this:
TestClass = { param = { n = 5 } }
function TestClass:new(o)
o = o or {}
setmetatable(o, self)
self.__index = self
return o
end
function TestClass:update(n)
n = n or 1
self.param.n = self.param.n + n
end
The issue is that when I instantiate an object like: obj = TestClass:new() the update method doesn't update the value stored in the obj table but instead it changes the value inside the default table: TestClass
Is there a way to fix this? I already looked up the tutorial by the creators of lua but they say nothing about tables as attributes.
I think you should do it like this then:
function TestClass:new(o)
o = o or { param = { n = 5 } }
setmetatable(o, self)
self.__index = self
return o
end
I solved this and the problem was that tables are stored by reference, not value so the solution was to create the table inside the o object at the time of instancing (the TestClass:new() method).
To do this automatically and only for params that are not passed in I wrote this little function:
function setDefaults(o, def)
for k,v in pairs(def) do
o[k] = o[k] or v
end
end
And it is simply used like this:
function TestClass:new(o)
o = o or {}
setDefaults(o, {
param = { n = 5 }
})
setmetatable(o, self)
self.__index = self
return o
end
I also wanted to thank a lot u/JackMacWindowsLinux and Ivo Beckers for helping me find this solution.

Lua: define functions from a table

NativeTable = {
["print"] = {},
["LoadResourceFile"] = {}
}
for k, v in pairs(NativeTable) do
k = function(...)
print("test")
end
end
this would result in defining them in the NativeTable and not as a global function
print = function(...)
print("test")
end
LoadResourceFile = function(...)
print("test")
end
So I'm trying to define a global function with a table name
Guess i could do smth like this
But there must be a better way?
NativeTable = {
["test"] = {},
["LoadResourceFile"] = {}
}
local function OverWriteFunction(FuncName, Func)
local Base = [[ = function(...)
print("jaa")
end
]]
local Final = FuncName .. Base
return Final
end
for k, v in pairs(NativeTable) do
load(OverWriteFunction(k))()
end
In your first example you are redefining the variable k, that is local inside the for loop, so this will not be usable outside the one loop where you define it.
Your second example is something you absolutely should avoid if you can, since defining code inside a string and loading it later means, that even only a syntax error will not be shown on "compiling" it, but only when that exact part is executed. And especially, when you are concatenating string that are meant to be code, you just get the risk of glueing something together wrongly, if you try to have that made generically.
If I understood correctly what you are trying to achieve, I would say, it could be something like this:
NativeTable = {
["test"] = {},
["LoadResourceFile"] = {},
[3] = {}
}
for k, v in pairs(NativeTable) do
if type(k) == "string" then
_G[k] = function(...)
print("output")
end
end
end
test()
LoadResourceFile()
-- _G[3]()
Which outputs:
output
output
What I have done here is to use the _G table which is the global environment of lua, all things you define there with a string in the brackets will be globally available (and what is globally available is inside that table, so be careful, since you can override other functions and variables you have defined!), even when writing it as a normal function call. I did also make sure, to only do this, when the type of k was string, otherwise you could start to define functions that can be called like the last commented out call.
This doesn't make too much sense for me:
NativeTable = {
["print"] = {},
["LoadResourceFile"] = {}
}
for k, v in pairs(NativeTable) do
k = function(...)
print("test")
end
end
First you create a table with table elements print and LoadResourceFile.
Then you iterate over that table and replace the table elements with functions.
Why not simply do this:
myTable = {
a = function() print("I'm function a") end,
b = function() print("I'm function b") end,
}
or
myTable = {}
myTable.a = function () print("I'm function a") end
Then you can call the global function like so: myTable.a()
If you insist on having those functions outside of a table you can simply insert them into the global environment table.
for k, v in pairs(myTable) do _G[k] = v end
then you could call a and b globally. But whatever you're trying to accomplish there's probably a better way than this.

__tostring in custom classes Lua

The following code should print 'hello', however it is printing the memory location of the table (i.e. 'table: 052E67D0'). Please, explain what I'm missing here.
TestClass = {}
function TestClass:new(o)
o = o or {}
setmetatable(o, self)
self.__index = self
return o
end
function TestClass:__tostring()
return "hello"
end
local t = TestClass.new{}
print(t)
Update
Tried doing this instead:
TestClass = {}
function TestClass:new(o)
o = o or {}
setmetatable(o, self)
self.__index = self
self.__tostring = function() return "hello" end
return o
end
local t = TestClass.new{}
print(t)
which worked. This seems weird because, to me, self in constructor and TestClass: refer to the same table.
Your TestClass:new takes two arguments and you call it with just one when you create t.
Change:
local t = TestClass.new{}
to:
local t = TestClass:new{}
Thanks to that self in this TestClass:new call is now reference to TestClass rather than to empty table which was (most likely) meant to be the new instance of the class.
In case of doubts please refer to Lua Reference Manual §3.4.10 or this stackoverflow question.

attempt to call method 'func' (a nil value)

No matter how I approach Lua, I run into this error all the time, so I must not understand something inherit to the language:
attempt to call method 'func' (a nil value)
I've seen the error here a few times as well but the problem doesn't seem clear to me.
Here's my module:
actor.lua
Actor = {
x = 0,
mt = {},
new = function()
local new_actor = {}
new_actor.x = Actor.x
new_actor.mt = Actor.mt
return new_actor
end,
test = function(self, a, b)
print(a, b)
end
}
I'm using Löve.
main.lua
require "game/actor"
local a = Actor:new() --works fine
function love.load()
a.x = 10
print(a.x) --output: 10
a:test(11, 12) --error: attempt to call method 'test' (a nil value)
end
I'm also not sure when it's appropriate to use the previous styling over this in a module.
Actor = {
x = 0
}
Actor.mt = {}
function Actor.new()
print(42)
end
I'm honestly not sure what is more correct than the other but considering I run into a simple error either way, there's probably something I'm missing entirely?
It looks like you're trying to instance a kind of class made of metatables. You basically need to assign new_actor's metatable with Actor.mt. (Resuming the problem: when you're indexing new_actor you're not indexing Actor in this case)
setmetatable(new_actor, Actor.mt);
Even if the metatable is being added, it won't work until you put the meta "__index" event to index a table containing your class methods/values, in this case:
Actor.mt = {
__index = Actor
};
I'd suggest moving your class methods/values into a new table, like Actor.prototype, Actor.fn, etc... avoiding conflicts:
Actor.fn = {
test = function(self, a, b)
print(a, b)
end
};
Actor.mt = {
__index = Actor.fn
};
More about metatables in Lua 5.3 manual.

When instantiating multiple instances of a lua object when to use require vs new?

I'm trying to wrap my head around the different ways to define and instantiate objects in Lua.
For the current problem, I'm imagining objects as simple as a C-struct (no methods necessary).
Between these two methods below, does it matter which way we choose? Is there a practical difference? I'd like to go for "least code" because I like "less code" best. It seems like the first method has a problem somewhere. Maybe it's just me. What happens if we instantiate 10,000 mary's? Does it matter?
First Way:
mary.lua
return {
name = "mary"
}
main.lua
local r = require("mary")
local s = require("mary")
local t = require("mary")
local u = require("mary")
Second Way:
mary.lua
local _O = {}
function _O:new()
o = {}
setmetatable(o, self)
self.__index = self
o:_create()
return o
end
function _O:_create()
self.name = "mary"
end
return _O
main.lua
local o = require("mary")
local r = o:new()
local s = o:new()
local t = o:new()
local u = o:new()
require is a function for loading modules, not instantiating classes.
require("mary") only loads mary.lua once, then stores the return value inside of package.loaded["mary"]. All subsequent results of require("mary") return the object at package.loaded["mary"], and do not create new instances. This makes require unsuitable for class instantiating.
local r = require("mary")
local s = require("mary")
print(rawequal(r, s)) -- Prints true
r.name = "samantha"
print(s.name) -- Prints samantha
Your second way actually creates new class instances. However, instead of a new class method, it's more familiar to call the class table itself, using the __call metamethod. I've written a one-file OOP framework that handles that and single inheritance; feel free to use it directly or as a reference.

Resources