I’ve been looking at great community sources on Roblox about OOP-like programming. and often I see stuff like:
local Table = {}
Table.__index = Table
And a .new() function, in which you’d set the this table as a metatable of the object?
I understand that metatable was necessary in order for the object to inherit the methods.
But my understanding was that if you set the methods to the “Table” , you would be able to use them outside of the module script so:
local Table = {}
function Table.doStuff() end
return Table
Other scripts could call the .doStuff()
What happens when you involve metatables, why do I need to __index for scripts to be able to use the methods? Is it to do with metatable inheritance of sorts? It seems counter intuitive to look for values in the same table that returned nil… (edit: by which I mean to look for a nil index in the same table…)
1 Like
You do not. This self.__index = self
trick is used in OOP. Unless you’re doing OOP, don’t do it.
Somewhat. Some people just like this way of defining their Class’s methods. Others might directly write to their new object.
local Class = {}
Class.__index = Class
function Class.new()
local New = {}
setmetatable(New, Class)
return New
end
function Class:Method()
print(self)
end
vs
local Class = {}
function Class.new()
local New = {}
function New:Method()
print(self)
end
return New
end
It may be important to note, when a function is called when it’s reference is derived from __index
the self
variable is the table who had a metatable with the __index
value, but not the value of the __index
value.
local A = {}
A.__index = A
local B = setmetatable({}, A)
function A:C()
print(self)
end
A:C() -- will print the memory location of A
B:C() -- will print the memory location of B; despite C coming from A
5 Likes
Ok, with your example:
Say in a new script you would do local newClass = Class.new()
and then you did newClass:Method()… so it looks for :Method in the newClass, doesn’t find it, goes to class, and presumably finds it… But how does that make sense? What I gather from metatables is that if you don’t find an index in one table, __index makes it to check in the metatable, but if that’s the same table, how come when you do :Method() on Class() it works, but it doesn’t on newClass, which is return setmetatable({}, Class) ? Just looking at the code it seems that you should be able to do:
local Class = {}
function Class.new()
local New = {}
setmetatable(New, Class)
return New
end
function Class:Method()
print(self)
end
… but if you referenced the return Class directly, you would, indeed, find the method…
… but apparently that’s not the case
I’ll check out the links, thanks.
1 Like
Because you’re setting New
's metatable to Class
; New
's __index
will also go back to Class
; so all methods of Class
are instantly “inherited.”
No; you need to some way define a __index
back to Class
.
Commonly people like to do Class.__index = Class
and set New
's metatable to Class
because it easily lets you overload other operators too.
local Class = {}
Class.__index = Class
function Class.new()
local New = {}
setmetatable(New, Class)
return New
end
function Class:Method()
print(self)
end
function Class:__add(x) --// __add metamethod `New` will have now becuase `Class` is New's metatable
return "i am being added on: " .. x
end
local Object = Class.new()
print(Object + 5)
Object:Method()
This is a good example. But you do understand what I’m confused about? It’s not the inheritance using the metatables (kind of), rather confusion over A already having the method defined, so the A.__index = A seeming redundant. In my mind I should be able to setmetatable({}, A), because A has the method, and __index seeming unnecessary =, because I wouldn’t be adding new functions dynamically, rather just define, but I think I’m starting to understand what’s happening… BTW… are functions indexes, if so, do they have values, or vise versa? Hope this’ll be my last post here …
1 Like
this is the least you can do to make OOP work
local A = {}
local MT = {}
MT.__index = A
function A.new ()
local self = {}
setmetatable(self, MT)
return self
end
If you have understood why, then doing A.__index = A
is just a small optimization as it says in the documentation.
Let’s say you create an object
local a = A.new()
then you expect to do this:
a.size = ...
local x = a.position
but you don’t expect to do this:
a.__index = ...
local x = a.__newIndex
because these indexes are reserved for the functioning of the metatables. That means that these indexes will never be used in your object, nor in your class.
Since the reserved indexes will never be used in class A
, and MT
will never use other indexes than the reserved ones, then A
could also act as MT
, A.__index = A
. Which is an optimization since you don’t need to create an extra table.
7 Likes