Zalokin
Zalokin

Reputation: 65

lua metatables - first parameter in __index function

I'm trying to learn metatables in Lua and I came across the following example: -

local my_metatable = {}

local my_tab = {}

setmetatable(my_tab, my_metatable)

-- Set the __index metamethod:
my_metatable.__index = function (tab, key)
    print("Hello, " .. key)
    return "cruel world"
end

-- Trigger the __index metamethod:
print("Goodbye, " .. my_tab["world"])

The result is:-

Hello, world
Goodbye, cruel world

My question is - what does the variable tab do, in my_metatable.__index = function (tab, key). I can change it to anything and it doesn't affect the program in any way.

Thanks!

;^) Zalokin

Upvotes: 0

Views: 1630

Answers (2)

younes askour
younes askour

Reputation: 58

My question is - what does the variable tab do, in my_metatable.__index = function (tab, key)

the tab arg is the table it self if you print the table outside the metamethod and then print the tab arg inside the metamethod you will that they have the same table address (think of it as self in python or this in c++)

I can change it to anything and it doesn't affect the program in any way.

this is wrong we can change the arg and it will affect the table (check the code above ):

local my_metatable = {}

local my_tab = {}

setmetatable(my_tab, my_metatable)

my_metatable.__index = function(tab, key)
    print("Hello, " .. key)
    print(tab)
    setmetatable(tab, {})
end

print("1", my_tab)
print("2", my_tab.blan)
print("3", my_tab.blan)

Explanation:

print("1", my_tab)

This prints the the memory address (reference) of my_tab.

print("2", my_tab.blan)

Accessing my_tab.blan triggers the __index metamethod :

  • It prints "Hello, blan".
  • It prints the memory address of my_tab.
  • It sets the metatable of my_tab to an empty table {}.

Since the __index metamethod changes the metatable of my_tab to {}, the original metatable with the __index metamethod is now gone. The __index function does not return any value, so the printed value is nil.

print("3", my_tab.blan)

Now, my_tab no longer has a metatable with an __index metamethod because it was overwritten by an empty table {} in the previous step. Accessing my_tab.blan again returns nil since blan is not defined in my_tab and there's no __index metamethod to handle it.

Final Output

Here is the summarized output of the code:

1   table: 0x<address>  -- address of `my_tab`
Hello, blan         -- from the `__index` metamethod
table: 0x<address>  -- address of `my_tab` (printed from within the `__index` metamethod)
2   nil              -- `my_tab.blan` after `__index` is removed
3   nil              -- `my_tab.blan` again

Upvotes: 0

NetherGranite
NetherGranite

Reputation: 2100

The tab parameter is passed an argument of the table itself.

For example, given your code my_tab["world"], the parameters tab and key will be passed the arguments my_tab and "world" respectively. Because you didn't use the table in your __index function, it didn't affect anything.

Here is a basic example of what it might be used for. Let us consider a special Array table that acts like an array but has some additional information:

Array = {
    length = 0,
    array = {}
}

mt = {
    __index = function(tab, index)
        return tab.array[index]
    end
}

setmetatable(t, mt)

--now when Array[3] is written, what will actually be returned is Array.array[3]

print(Array[3]) --will actually print Array.array[3]

This isn't actually the best way to implement this functionality, but hopefully this gives you an idea of why the tab parameter exists and what __index can be used for as a result.

Upvotes: 0

Related Questions