Executing Functions In a Table During Iteration

Hello,

I'm attempting to create a system where a table containing a function executes that function upon encountering it.

Given a function:

function doAThing(arg1, arg2)
--dostuff
end

And given a table:

story={
[1]="Once upon a time..."
,[2]="Long ago..."
,[3]="So long ago that everyone forgot..."
,[4]=doAThing(3,"foobar")
}

And finally, given a way to iterate through the table:

for i,v in pairs(story) do
if type(v) == "string" then
print(v)
elseif type(v) == "function" then
do function?
end
end

How would I execute the function the iterator has found?

Thanks!

doAThing(3,"foobar") will call doAThing right away, and so the result of that function will become the value of story[4].

What you could do is make doAThing itself return a function. That function will still have access to the arguments passed into doAThing. Then in your loop, do v() to call that function:

function doAThing(arg1, arg2)
  return function ()
    print("doing a thing!", arg1, arg2)
  end
end

story={
 [1]="Once upon a time...",
 [2]="Long ago...",
 [3]="So long ago that everyone forgot...", 
 [4]=doAThing(3,"foobar")
}

for i,v in ipairs(story) do
  if type(v) == "string" then
    print(v)
  elseif type(v) == "function" then
    -- calls the function returned by doAThing
    v()
  end
end

You might also notice that I swapped pairs for ipairs here -- this will make sure you iterate through the table in the order you expect!

1 Like

You need to store a reference to your function in the table, but as you’ve written it, you’re calling the function when you define your table, and storing the result. Instead of using calling syntax with () you should just put the name of the function in your table, like so:

story = {
    …,
   [4]=doAThing,
    …
}

Then you can call the function using () in your loop:

…
elseif type(v) == "function" then
    v()
end
…

You're probably asking: "what about the arguments?" To do it this way, you'd need to store your arguments separately, perhaps by storing a table with both the function itself, and a list of arguments:

story = {
    …,
   [4]={fn = doAThing, args = {3, "foobar"}},
    …
}

Then to call it:

…
elseif type(v) == "table" then
    v.fn(table.unpack(v.args))
end
…

Alternatively, you could create an anonymous wrapper function (i.e. a "thunk") which takes no arguments and will delay computation of the inner function until you're ready:

story = {
    …,
   [4]=function() doAThing(3, "foobar") end,
    …
}

Then just call it as in the first example:

…
elseif type(v) == "function" then
    v()
end
…

The latter option is probably easiest!

Thank you both so much for your help!

All the solutions worked out in my testing, so I'll keep them in my back pocket for future reference!