View Single Post
06-11-15, 02:05 PM   #1
Mayron
A Frostmaul Preserver
 
Mayron's Avatar
AddOn Author - Click to view addons
Join Date: Jan 2010
Posts: 275
Issue with iterating through values with metatables

Hi,

I don't know exactly how the pairs, ipairs, and next iterator functions in Lua work, only what they do but still I thought they have to access index's of a table but they seem to have strange results on metatable's which is very annoying to work with:

Lua Code:
  1. -- test:
  2. local realTable = {
  3.     "hello",
  4.     "something",
  5.     aValue = true,
  6. }
  7.  
  8. local someTable = setmetatable({}, {__index = realTable})
  9. for key, value in pairs(someTable) do
  10.     print(key) -- never gets printed
  11. end

or:

Lua Code:
  1. -- test:
  2. local realTable = {
  3.     "hello",
  4.     "something",
  5.     aValue = true,
  6. }
  7.  
  8. local sometable = setmetatable({}, {__index = realTable})
  9. for id, value in ipairs(sometable) do
  10.     print(value) -- never gets printed
  11. end
  12.  
  13. print(sometable[1]) -- prints "hello" as expected

These test examples show my point. Both ipairs and pairs, no matter what is in the "realTable" (index/value pairs or key/value pairs) will never access the meta method __index to go to the realTable. I can sort of understand why pairs will not work but ipairs tries to access the first index [1] of someTable which does not exist so shouldn't it attempt to call the __index meta method?
Also if I replace pairs/ipairs with the "next" function I get an "attempt to call a nil value" Lua error instead which seems even more strange to me.

I understand that pairs does not directly look for "aValue" in the someTable but is it possible to achieve the result of looking inside the realTable instead using these iterator functions as a way around this?

Thanks for reading


EDIT: I have read the documentation from lua.org about how ipairs works and still cannot understand why the __index method is not triggered:

Originally Posted by http://www.lua.org/pil/7.3.html
Lua Code:
  1. function iter (a, i)
  2.     i = i + 1
  3.     local v = a[i] -- here someTable (a) is being directly indexed by i so it's meta method __index should be called but it doesn't!
  4.     if v then
  5.         return i, v
  6.     end
  7. end
  8.  
  9. function ipairs (a) -- In my case, a would be someTable
  10.     return iter, a, 0
  11. end

When Lua calls ipairs(a) in a for loop, it gets three values: the iter function as the iterator, a as the invariant state, and zero as the initial value for the control variable. Then, Lua calls iter(a, 0), which results in 1, a[1] (unless a[1] is already nil). In the second iteration, it calls iter(a, 1), which results in 2, a[2], and so on, until the first nil element.

Shouldn't line "local v = a[i]" call this method? Because this should equivalate to "local v = someTable[i]" which is an attempt to access an index which does not exist in someTable which should mean it calls __index to check the realTable instead. But it doesn't do this!

_

Last edited by Mayron : 06-11-15 at 05:09 PM.
  Reply With Quote