What is the connection between the __index meta method and meta tables?

General discussion about LÖVE, Lua, game development, puns, and unicorns.
Post Reply
User avatar
ddabrahim
Party member
Posts: 182
Joined: Mon May 17, 2021 8:05 pm
Contact:

What is the connection between the __index meta method and meta tables?

Post by ddabrahim »

Hi.

I trying to learn how to do OOP in Lua and while I did find working solutions, I don't actually understand how it works. So I am trying to better understand why and how things works in Lua. But I have a hard time with it.

Could someone please help me explaining the relationship between the .__index meta method and the setmetatable() method?

I did read documents and watched tutorial videos including the one from Jeeper but I just don’t understand it.

This is what I am trying to do to help me understand:

I have 2 tables

Code: Select all

human = {age = 12}
student = {grade = 5}

student.__index = student
setmetatable(student,human)

function love.draw()
  love.graphics.print(""..student.age)
end
It works, but I do not understand why.

I understand I set human as the parent table of student and so student can access the age property of human.
What I don’t understand however is that I need to set the .__index of student to point to it self in order for this to work. I simply can not figure out why do I have to do this.

Some tutorials saying if I would do

student.__index = human

On it’s own it would point to the table human and I could call student.age but it is not true. For this to work I need to setmetatable(student,student) and then I can call student.age which is just even more confusing.

Could anyone please explain it in layman's terms what is happening here, what is the connection between .__index and setmetatable()?

Thank you in advance.
User avatar
ReFreezed
Party member
Posts: 612
Joined: Sun Oct 25, 2015 11:32 pm
Location: Sweden
Contact:

Re: What is the connection between the __index meta method and meta tables?

Post by ReFreezed »

I think some confusion is caused by some tables being reused for multiple things. I'll try to explain how things work.

Code: Select all

do
	-- This object will represent the Human "class" and has all "fallback"
	-- values for table fields that human instances don't have.
	local Human = {age=12} -- This will be the __index metamethod.

	-- This will be the metatable that human instances will use.
	local HumanMetatable = {__index=Human}

	-- Here's an instance of our Human class. It's just a normal table so far.
	local someHuman = {}
	print("before setmetatable:", someHuman.age) -- nil, as we haven't set the metatable yet.

	setmetatable(someHuman, HumanMetatable)
	print("after setmetatable: ", someHuman.age) -- 12

	-- Because someHuman doesn't have an 'age' field (i.e. it's nil) Lua falls
	-- back to using the __index metamethod of the metatable (i.e.
	-- HumanMetatable.__index) to determine what value someHuman.age should
	-- return.

	-- Note that Lua simply returns HumanMetatable.__index.age here, i.e. Lua
	-- does a normal table lookup for an 'age' field in the table
	-- HumanMetatable.__index. (This will be important when we extend the
	-- Human class later.)
end

do
	-- As you see above, we're using two tables for the meta-functionality of
	-- our "human" objects - Human and HumanMetatable. This is not necessary -
	-- we can save a table by using Human as both the __index metamethod and
	-- the metatable itself. (This seems to cause some confusion.)

	local Human   = {age=12} -- Human is both the __index metamethod...
	Human.__index = Human    -- ...and the metatable!

	local someHuman = {}
	setmetatable(someHuman, Human) -- We can now use Human instead of HumanMetatable.
	print("human age:  ", someHuman.age) -- 12

	-- Now, let's extend the Human class with the subclass 'Student'.
	local Student   = {grade=5}
	Student.__index = Student -- Again with the same trick of reusing one table for both the metatable and the metamethod.

	-- We use setmetatable() the same way when we connect subclasses to parent
	-- classes as when we connect class instances to their class. We're just
	-- creating a table lookup "chain".
	setmetatable(Student, Human)

	local someStudent = {}
	setmetatable(someStudent, Student)
	print("student age:", someStudent.age) -- 12

	-- Here are all steps Lua takes to get the value 12:
	-- * Lua looks up someStudent.age - it's nil!
	-- * someStudent has a metatable, so...
	-- * Lua looks up getmetatable(someStudent).__index.age - it's nil!
	-- * getmetatable(someStudent).__index also has a metatable, so...
	-- * Lua looks up getmetatable(getmetatable(someStudent).__index).__index.age - it's 12!
	-- * Lua returns 12.
end
Tools: Hot Particles, LuaPreprocess, InputField, (more) Games: Momento Temporis
"If each mistake being made is a new one, then progress is being made."
User avatar
pgimeno
Party member
Posts: 3541
Joined: Sun Oct 18, 2015 2:58 pm

Re: What is the connection between the __index meta method and meta tables?

Post by pgimeno »

ddabrahim wrote: Wed Nov 03, 2021 7:41 am

Code: Select all

human = {age = 12}
student = {grade = 5}

student.__index = student
setmetatable(student,human)

function love.draw()
  love.graphics.print(""..student.age)
end
It works, but I do not understand why.
No wonder, because it's not supposed to work. And indeed, when I test it I get:

Code: Select all

Error: student.lua:8: attempt to concatenate field 'age' (a nil value)
stack traceback:
	[string "boot.lua"]:777: in function '__concat'
	student.lua:8: in function 'draw'
	[string "boot.lua"]:618: in function <[string "boot.lua"]:594>
	[C]: in function 'xpcall'
So no, it doesn't work.

See if this is of any help: https://codeberg.org/pgimeno/Gists/src/ ... e-tutorial
User avatar
zorg
Party member
Posts: 3435
Joined: Thu Dec 13, 2012 2:55 pm
Location: Absurdistan, Hungary
Contact:

Re: What is the connection between the __index meta method and meta tables?

Post by zorg »

To add to ReFreezed's answer above, it can also be a bit confusing that while metamethods would need to be... well, methods (functions), lua allows __index to be a table as well, but it's still called the index metamethod.
Me and my stuff :3True Neutral Aspirant. Why, yes, i do indeed enjoy sarcastically correcting others when they make the most blatant of spelling mistakes. No bullying or trolling the innocent tho.
User avatar
ddabrahim
Party member
Posts: 182
Joined: Mon May 17, 2021 8:05 pm
Contact:

Re: What is the connection between the __index meta method and meta tables?

Post by ddabrahim »

Thank you for the replies, much appreciated.
I'll try to explain how things work.
Thanks a lot. The way you explain it and the concept sounds so simple and helped me to see this from a different perspective.
This is the way I see this right now.

Code: Select all

student.age --nil so Lua going to look up the metatable of student.

setmetatable(student, human) --in this case the student has a metatable called human and so Lua go and look up the __index of human

human.__index = human --because the __index of human is point to the human table student.age will return a value  
OR

Code: Select all

setmetatable(student,student) --in this case student is also the metatable and Lua going to look up the __index of student

student.__index = human --because the index of student is point to the human table, student.age return a value
The way I think about this and the way I am describing is probably incorrect, but at the moment this perspective is more simple for me to think about it. I'm going to need some more time to get my head around this but for now I think this new perspective is working...
No wonder, because it's not supposed to work.
Sorry, not too sure why I believed it is working but now using my new perspective, I can see that it is indeed not supposed to.
Thank you for the link I'm going to attempt to learn from it.
metamethods would need to be... well, methods (functions), lua allows __index to be a table as well, but it's still called the index metamethod.
Yes at the moment I am so confused when, why and how to use it. But maybe I am on track now.

Thank you all!
Post Reply

Who is online

Users browsing this forum: No registered users and 19 guests