__tostring in custom classes Lua - 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.

Related

Why doesn't the __call metamethod work in this Lua class?

in the code below, i set up a __call metafunction which, in theory, should allow me to call the table as a function and invoke the constructor, instead of using test.new()
test = {}
function test:new()
self = {}
setmetatable(self, self)
--- private properties
local str = "hello world"
-- public properties
self.__index = self
self.__call = function (cls, ...) print("Constructor called!") return cls.new(...) end
self.__tostring = function() return("__tostring: "..str) end
self.tostring = function() return("self:tstring(): "..str) end
return self
end
local t = test:new()
print(t) -- __tostring overload works
print(tostring(t)) -- again, __tostring working as expected
print(t:tostring()) -- a public call, which works
t = test() -- the __call metamethod should invoke the constructor test:new()
output:
> __tostring: hello world
> __tostring: hello world
> self.tostring(): hello world
> error: attempt to call global `test` (a table value) (x1)
(i'm using metatable(self, self) because i read somewhere it produces less overhead when creating new instances of the class. also it's quite clean-looking. it may also be where i'm getting unstuck).
You're setting the __call metamethod on the wrong table - the self table - rather than the test table. The fix is trivial:
test.__call = function(cls, ...) print("Constructor called!") return cls.new(...) end
setmetatable(test, test)
After this, test(...) will be equivalent to test.new(...).
That said, your current code needs a refactoring / rewrite; you overwrite the implicit self parameter in test:new, build the metatable on each constructor call, and don't even use test as a metatable! I suggest moving methods like tostring to test and setting the metatable of self to a metatable that has __index = test. I'd also suggest separating metatables and tables in general. I'd get rid of upvalue-based private variables for now as they require you to use closures, which practically gets rid of the metatable benefit of not having to duplicate the functions per object. This is how I'd simplify your code:
local test = setmetatable({}, {__call = function (cls, ...) return cls.new(...) end})
local test_metatable = {__index = test}
function test.new()
local self = setmetatable({}, test_metatable)
self._str = "hello world" -- private by convention
return self
end
function test_metatable:__tostring()
return "__tostring: " .. self._str
end
function test:tostring()
return "self:tstring(): " .. self._str
end
If you like, you can merge test and test_metatable; I prefer to keep them separated however.

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.

How does setmetatable() work and why the metatable is needed in the linked list in lua

I'm learning how Lua's metatables work in OOP, and I am confused of the code I read from the object orientation tutorial on lua-users wiki. Could someone helps to explain the following questions? Thanks.
Question 1:
The wiki's explanation: Here we add a metatable to the class table that has the __call metamethod, which is triggered when a value is called like a function. We make it call the class's constructor, so you don't need the .new when creating instances.
(1)How does the __call get called in the example so the constructor is called?
(2)Does "cls" refer to "MyClass?"
setmetatable(MyClass, {
__call = function (cls, ...)
return cls.new(...)
end,
})
Question 2:
What does {} from the following code refer to?
function MyClass.new(init)
local self = setmetatable({}, MyClass)
self.value = init
return self
end
**Here is the Complete code:
local MyClass = {}
MyClass.__index = MyClass
setmetatable(MyClass, {
__call = function (cls, ...)
return cls.new(...)
end,
})
function MyClass.new(init)
local self = setmetatable({}, MyClass)
self.value = init
return self
end
function MyClass:set_value(newval)
self.value = newval
end
function MyClass:get_value()
return self.value
end
local instance = MyClass(5)
-- do stuff with instance...
Question 1:
setmetatable(MyClass, {
__call = function (cls, ...)
return cls.new(...)
end,
})
This sets MyClass's metatable to a table which defines the __call metamethod. Because of that, you can 'call' MyClass (newObj = MyClass(<args>)). In the metamethod, cls refers to the table that is called, in this case it refers to MyClass.
Question 2:
function MyClass.new(init)
local self = setmetatable({}, MyClass)
self.value = init
return self
end
{} is syntax for a table literal, which creates a new table (an empty one in this case). The MyClass table is set as the metatable for a new table. Then this new table is assigned to self.
More about metatables can be found here: https://www.google.com/?gws_rd=ssl#q=lua+metatables as suggested by Anderson Green in the comments.

Classes in Lua, how does it work

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()

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