5

A Lua newbie here. Can I store function references as keys in a Lua Table? Something similar to this:

local fn = function() print('hello') end
local my_table = {}
my_table[fn] = 123

This does seem to work fine but I don't know if I can rely on the uniqueness of the function references. Can Lua reuse function references once they are out of scope? Can this create any issues or is it considered a bad practice due to some reason?

hjpotter92
  • 78,589
  • 36
  • 144
  • 183
Vivek
  • 51
  • 1
  • 4

4 Answers4

6

Yeah. One of the best things I've encountered in lua is the anything as references property.

There's nothing wrong with the way you are using your keys in the table.

From Lua PiL

Tables in Lua are neither values nor variables; they are objects.You may think of a table as a dynamically allocated object; your program only manipulates references (or pointers) to them. There are no hidden copies or creation of new tables behind the scenes.

In your example, you haven't passed any argument to the function, so basically, it'll be useless in your case to have functions as reference in the program. On the other hand, something like this:

fn1 = function(x) print(x) end
fn2 = function(x) print("bar") end
t[fn1] = "foo"
t[fn2] = "foo"
for i, v in pairs(t) do i(v) end

does have its uses.

Can Lua reuse function references once they are out of scope?

As long as your parent table is in scope, yes. Since tables are created and manipulated but not copied, so there isn't a chance that your function reference can be deprecated from the table index memory. I'll edit this answer later after trying it out actually too.

Can this create any issues or is it considered a bad practice due to some reason?

It's just considered a bad practise because users familiar with other languages, like C, python etc. tend to have array in mind when reading tables. In you have no such worries, and the program will work perfect.

I don't know if I can rely on the uniqueness of the function references.

Why?

Community
  • 1
  • 1
hjpotter92
  • 78,589
  • 36
  • 144
  • 183
  • Thanks for the detailed answer! Much appreciated! I doubted the uniqueness of function references as there may be a rare case where two functions have same body and the Lua interpreter may decide to make it a single reference to save memory, as happens in case of empty objects and same strings in most languages. That said, the case of two functions with same bodies should not arise in most projects. Other reason was can Lua use the same hashcode(the one seen by printing function or calling tostring(fn)) for other functions. But as you clarified, this is unlikely unless it is gc'ed. – Vivek Jan 28 '13 at 14:37
  • Even with the same body, as long as you use separate `name`s for them, they **WILL** be assigned new reference. – hjpotter92 Jan 28 '13 at 14:40
  • 2
    @BackinaFlash that is not true in general. That was true for the 5.1 official interpreter; but is NOT for 5.2. I believe it was up to the individual implementaton. – daurnimator Jan 29 '13 at 08:31
3

The uniqueness of the function references depends on Lua version.

Lua 5.2 manual says:
a function definition may not create a new value; it may reuse some previous value if there is no observable difference to the new function

Example:

-- 10 different function references on Lua 5.1
-- The same function reference for Lua 5.2
local j
for i = 1, 10 do
   print(function() print(j) end)
end

-- 10 different function references for any Lua version
for i = 1, 10 do
   print(function() print(i) end)
end

So, the rule is: create different closures to get different references.

Egor Skriptunoff
  • 23,359
  • 2
  • 34
  • 64
  • Thanks Egor! That is an important thing to know. However I don't expect two functions with same bodies in my project so it should not matter. – Vivek Jan 29 '13 at 13:05
  • Also if we create the two functions with same bodies in different scopes, say as values in different tables, then they do get unique references, so that addresses whatever little chance there is for same body functions. – Vivek Jan 29 '13 at 13:19
1

You can do that, function will remain in the same place of memory until it is destroyed (by garbage collector).

You can try in interactive lua:

> fn = function() print('hello') end
> print(fn)
function: 0x9d058d0

> fn2 = function() print('hello') end
> print(fn2)
function: 0x9d05ee8

> fn2=fn
> print(fn2)
function: 0x9d058d0

> print(function() print('hello') end)
function: 0x9d068a8

> print(function() print('hello') end)
function: 0x9d06bf8

Remember that if fn is local it'll be garbage collected when goes out of scope. In your case it shouldn't be a problem as my_table is local in the same block. See Lua documentation on local variables.

zxxc
  • 355
  • 3
  • 12
1

This does seem to work fine but I don't know if I can rely on the uniqueness of the function references.

Every function() end statement creates a new closure. The actually code of a function will be reused if it comes from the same constructor:

for i=1,100 do
    t[function() print(i) end] = i -- this function body will be reused
end

But each closure will be unique, and that's what matters for your reference.

Can Lua reuse function references once they are out of scope?

Lua's not going to collect fn as long as it's used as a key in my_table. If my_table goes out of scope, too, such that both table and function get collected, then Lua reusing the reference wouldn't affect you. So either way, you're good.

Mud
  • 28,277
  • 11
  • 59
  • 92