Daniel
Daniel

Reputation: 299

Iterating over a table and calling a method in lua

I'm trying to iterate over a table of functions, and call each function one by one. I keep getting the 'attempt to access a field/method NIL value. Some of them are obvious, but some of them baffle me.

 tests={}

function tests.test1()
    print("test1 running\n")
end


function tests.test2()
    print("test2 running\n")
end


function tests.test3()
    print("test3 running\n")
end

print(tests)

-- why is tests.i() or tests:i not working?
for i,x in pairs(tests) do
    print("x is")
    print(x)
    print("i is")
    print(i)

    --tests.i()  -- attempt to call field i a NIL value
    --tests.i(tests) -- ditto
    --tests:i() -- attempt to call method i, a NIl value
    --tests:i(tests) -- ditto 
    tests[i]() -- works!

    --tests.x() -- attempt to call field x, a NIl value
    --tests.x(tests) -- ditto
    --tests:x() -- attempt to call method x, a NIL value
    --tests[x]() -- attempt to call field ? a NIl value
end

--all these work
tests.test1(tests)
tests:test1()

tests.test2(tests)
tests:test2()

tests.test3(tests)
tests:test3()

Why is the tests.i() method not working, or tests.i(tests), if it's expecting a 'self' argument, in which case why isn't tests:i() working? The last bit shows all of them working when called outside the loop, which makes it even more difficult to understand.

Upvotes: 1

Views: 445

Answers (2)

Piglet
Piglet

Reputation: 28940

tests.i() is syntactic sugar for tests["i"](). tests:i() is syntactic sugar for tests["i"](tests).

In your loop ? for i, x in pairs(tests) do, i is "test1", "test2" and "test3" in the respective loop cycle. So tests[i]() resolves to tests["test1"]() and so forth, which is tests.test1()

Make sure you understand that tests.i is short for tests["i"], not tests[i]! So in one case you index tests with a string "i" while in the second case you'll index it with the value of the variable i which in your case is one of the keys of tests.

In a loop like yours the values are functions so you can simply call x intead of calling tests[i] btw.

Upvotes: 3

Doyousketch2
Doyousketch2

Reputation: 2147

that inserted-arg will get thrown away when calling tests:test1() unless you specify a placeholder for it.

tests = {}
function tests.test1( a )  --  you can only use args you've accounted for
    local a = a or ''
    print( 'test1 running', a )
end

you can also call x() to execute those functions from your loop.

-- test i, test i.  1, 2, 3?
for i, x in pairs( tests ) do
    print(  string.format('i is "%s"', i )  )
    print( 'x is', x )

    x()  --  same as calling  tests["i"]()
end

tests:test1()

i is "test1"
x is function: 0x1420f20
test1 running
test1 running table: 0x1421f10

Upvotes: 2

Related Questions