• Announcement: Lua.org now officially recommends this forum as a meeting place for the Lua community

Is there a way to reffer a table itself inside the same table? (1 Viewer)

Herly Quijano

Newcomer
Joined
Mar 19, 2021
Messages
70
Reaction score
7
I searched and I didn't find anything, what I ask if I can do something like this, just to put an example:
Lua:
t={
    val=3
    ,EditVal=function()
        t.val=4
    end
}

print(t.val) --Should print 3
t.EditVal()
print(t.val) --Should print 4
 

stetre

Member
Rank: I
Joined
Jan 8, 2020
Messages
95
Reaction score
55
Location
Italy
Website
github.com
No, you have to pass the table itself as argument to the function:

Lua:
t={
    val=3
    ,EditVal=function(t) --<------ 
        t.val=4
    end
}

print(t.val) --Should print 3
t.EditVal(t)
print(t.val) --Should print 4

-- You can also use the 'colon syntax' to execute the function:
t:EditVal() -- same as t.EditVal(t)
 

Herly Quijano

Newcomer
Joined
Mar 19, 2021
Messages
70
Reaction score
7
I searched about that and this is what I understand, the equivalent for what I want with colon syntax is:
Lua:
t={
    val=3
    ,EditVal=function(self)
        self.val=4
    end
}

print(t.val) --Should print 3
t:EditVal()
print(t.val) --Should print 4
Right?

Edit, now I have another question, if 2 tables have a method with the same name, Can't I use the colon syntax?
Lua:
t={
    val=3
    ,EditVal=function(self)
        self.val=4
    end
}

s={
    ,EditVal=function(self)
        self.val=4
    end
}

t:EditVal() --What does this?
Right?
 
Last edited:

stetre

Member
Rank: I
Joined
Jan 8, 2020
Messages
95
Reaction score
55
Location
Italy
Website
github.com
As for the 'self', it's just the name of the function argument. Its scope is limited to the function. I called it 't', you called it 'self', but you can call it whatever you want (bar reserved keywords, of course). I personally don't like using 'self' that much because I feel that when there are too many 'self' in a script the code becomes unreadable.

Regarding the second question, x:f(a, b, c) is just synctatic sugar. It's exactly the same as writing x.f(x, a, b, c). Thus:

Lua:
t:EditVal( )
-- is the same as:
t.EditVal(t)

That is, it executes the EditVal member of t, passing t as argument (i.e. as 'self'). The end result is to assign 4 to t.val.
 

Herly Quijano

Newcomer
Joined
Mar 19, 2021
Messages
70
Reaction score
7
As for the 'self', it's just the name of the function argument. Its scope is limited to the function. I called it 't', you called it 'self', but you can call it whatever you want (bar reserved keywords, of course). I personally don't like using 'self' that much because I feel that when there are too many 'self' in a script the code becomes unreadable.

Regarding the second question, x:f(a, b, c) is just synctatic sugar. It's exactly the same as writing x.f(x, a, b, c). Thus:

Lua:
t:EditVal( )
-- is the same as:
t.EditVal(t)

That is, it executes the EditVal member of t, passing t as argument (i.e. as 'self'). The end result is to assign 4 to t.val.
Oh ok, I got it. PD: I think I should put somthing like s.EditVal(self) does set self.val=5 to make more understandable what I said, but I think you understood it anyway.
 

stetre

Member
Rank: I
Joined
Jan 8, 2020
Messages
95
Reaction score
55
Location
Italy
Website
github.com
All right. Now, if my assumption is correct and you're heading to object oriented programming, the next step would be to introduce metatables.

That is, you can put the EditVal function in a table as 'mt' in the code below, and then set this table as the metatable of t, of s, and of any other similar 'object' you want to create. This way, all these objects will have the EditVal 'method'.

Lua:
mt = {  __index = { EditVal = function (x) x.val = 4 end } }

t = { val = 3 }
setmetatable(t, mt)

s = { val = 1 }
setmetatable(s, mt)

t:EditVal( ) -- this sets t.val = 4
s:EditVal( ) -- this sets s.val = 4
 

Herly Quijano

Newcomer
Joined
Mar 19, 2021
Messages
70
Reaction score
7
All right. Now, if my assumption is correct and you're heading to object oriented programming, the next step would be to introduce metatables.

That is, you can put the EditVal function in a table as 'mt' in the code below, and then set this table as the metatable of t, of s, and of any other similar 'object' you want to create. This way, all these objects will have the EditVal 'method'.

Lua:
mt = {  __index = { EditVal = function (x) x.val = 4 end } }

t = { val = 3 }
setmetatable(t, mt)

s = { val = 1 }
setmetatable(s, mt)

t:EditVal( ) -- this sets t.val = 4
s:EditVal( ) -- this sets s.val = 4
Oh nice, it will work better, in what section I can learn more of this?
Edit: I found it in the sections 13 and 16 of the reference manual.
 
Last edited:

Herly Quijano

Newcomer
Joined
Mar 19, 2021
Messages
70
Reaction score
7
Question, for what I do, how can I do inheritance? I read but I don't end of understand it.
 

stetre

Member
Rank: I
Joined
Jan 8, 2020
Messages
95
Reaction score
55
Location
Italy
Website
github.com
Question, for what I do, how can I do inheritance? I read but I don't end of understand it.

That's what inheritance is for: making things hard to understand, with almost none of the heralded benefits (like most oop, btw).

However, if you reeeeeally want to do it, you just have to realize that the tables you assign to fields like __index and __newindex are regular tables, so they also can have metatables. Consider this example, and possibly try it out:

Lua:
super_mt = { __index = {
    f=function(x) print("super f()") end,
    g=function(x) print("super g()") end,
}}

sub_mt = { __index = {
    f=function(x) print("sub f()") end,
}}

setmetatable(sub_mt.__index, super_mt)

t = {}
setmetatable(t, sub_mt)

t:f() -- (1)
t:g() -- (2)

At (1), since t doesn't have a member named f, the interpreter searchs for it in the __index table of its metatable (sub_mt). It finds it, and executes it.

At (2), the same happens for the member named g, but this time the sub_mt.__index table doesn't have such a member so the interpreter searches it in the __index table of the metatable of sub_mt.__index (super_mt). And so on... you can chain as many metatables you like, and implement a perfect obfuscator in the classic OOP way. ;-)
 

stetre

Member
Rank: I
Joined
Jan 8, 2020
Messages
95
Reaction score
55
Location
Italy
Website
github.com
Thank you, but what do you mean with this?

I don't like OOP that much. I find that it almost always leads to overly complicated software architectures that are both difficult to understand and hard to maintain. Which is ironic since one of its biggest selling point is (or was) that it helps producing code that is more maintainable.

This is just a personal opinion, though. If you like OOP, Lua may be a pain to use (at first, at least) because it provides only basic mechanisms for prototype-based programming. People have written modules to implement more familiar OOP constructs on top of those basic mechanisms. Just google "lua oop module" and you can find a bunch of them.
 

Herly Quijano

Newcomer
Joined
Mar 19, 2021
Messages
70
Reaction score
7
@stetre I understand you, I'm programming in Java too and this things with the classes sometimes can be a headache (And is really useful use anything as an index), I don't wanna try to emulate 100% the OOP in Lua, but I just wanna do this to have it more organized.
 

Herly Quijano

Newcomer
Joined
Mar 19, 2021
Messages
70
Reaction score
7
I tested and I noticed that if they can be a chain of metatables Lua doesn't search fields in the metatable of a metatable
Lua:
local t = {}

setmetatable(t, {__index = {}})

setmetatable(getmetatable(t), {__index = {hola = 3}})

print(t)
print(getmetatable(t))
print(getmetatable(getmetatable(t)))

print(t.hola)
Prints:
Code:
table: 00000299c5549270
table: 00000299c5548d30
table: 00000299c5548d70
nil
And
Lua:
local t = {}

setmetatable(t, {__index = {hola = 3}})

print(t)
print(getmetatable(t))
print(getmetatable(getmetatable(t)))

print(t.hola)
Prints
Code:
table: 000001215e108c70
table: 000001215e109070
nil
3
So that method doesn't work, so I think my better option is merge metatables, but I'm note sure about the methods I found for there, do you know a good method?
 

stetre

Member
Rank: I
Joined
Jan 8, 2020
Messages
95
Reaction score
55
Location
Italy
Website
github.com
To chain metatables you have to set the __index field of the metatable of the child, not the metatable of the child. See the example I posted earlier.

I know it's a bit confusing. Think like this: when Lua tries to access a non existing field of a table, it looks if it has a metatable, and if it has one it looks in its __index field (not in the metatable itself). So it's the metatable of the __index that you have to set if you want the search to continue in case the field is still missing.

(To be precise, Lua looks for __index, or __newindex, or other __xxx fields, depending on the operation. See 2.4 Metatables and Metamethods ).
 

Herly Quijano

Newcomer
Joined
Mar 19, 2021
Messages
70
Reaction score
7
Question, the functions rawset and rawget are faster than use the normal "table[key] = value"?, because they act without using the metamethods __index and __newindex respectively.
 

stetre

Member
Rank: I
Joined
Jan 8, 2020
Messages
95
Reaction score
55
Location
Italy
Website
github.com
Question, the functions rawset and rawget are faster than use the normal "table[key] = value"?, because they act without using the metamethods __index and __newindex respectively.

They should be faster, but the comparison is meaningful only in the case that the table doesn't have a metatable, in which case they probably aren't that faster since the lack of a metatable is detected almost immediately.

On the other hand, if the table has a metatable then their behaviour is different than regular table accesses, so one would likely choose depending on the desired behavior, not on performance.
 

stetre

Member
Rank: I
Joined
Jan 8, 2020
Messages
95
Reaction score
55
Location
Italy
Website
github.com
I honestly don't know. My guess is that it shouldn't be very different, but of course if you are doing really heavy computations the differences could add up to the point of being relevant. To have a more precise idea you should do some measures.

In my opinion, however, when you feel the need for these sort of optimizations it's a clear sign that you are implementing in Lua parts that you'd better implement in C or C++ (perhaps as routines exposed to Lua code via the Lua C-API).
 
Top