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?
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 lua 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?
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.
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.
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.
Related
I have been playing with Lua for the past week and I ended up writing this peace of code. I find it really useful that you can dynamically create new functions that "inherit" other functions, so programmers must have a name for it. My questions are:
What is this called?
Is there a better way to do this? (cycle over a data structure and create add-on functions that "improve" existing functions)
D = {
name = {
value = nil,
offset = 0,
update = function (self)
self.value = "Berlin"
end,
},
}
--Dynamic function definition
for i in pairs(D) do
D[i].upAndWrite = function(self)
self:update()
print("upAndWrite was here")
end
end
print(D.name.value)
D.name:upAndWrite()
print(D.name.value)
Result:
nil
upAndWrite was here
Berlin
I don't think that what you're doing have special name for it, it's just on-the-fly function creation.
There are few notes regarding your code:
Proper for loop
for i in pairs(D) do
…
end
In programming, variable i is generally used for counter loops, like in
for i=1,100 do
…
end
Here, pairs returns an iterator function and the idiomatic way to use it is
for k,v in pairs(D) do
…
end
Here k is a key (like i in your code) and v is a value (use it instead of indexing table like D[k] or D[i] in your code when you need to access the corresponding value).
There's no need to create functions on the fly!
Another important thing is that you create new function on each loop iteration. While this feature is very powerful, you're not using it at all as you don't store anything using upvalues and only access data through arguments.
A better way to do it would be creating function once and assigning it to every field:
-- Define D here
do
local function upAndWrite(self)
self:update()
print("upAndWrite was here")
end
for k,v in pairs(D) do
v.upAndWrite = upAndWrite -- Use our function
end
end
-- Perform tests here
What does on-the-fly function creation allow?
As mentioned above, you can utilize this very powerful mechanism of closures in certain situations. Here's a simple example:
local t = {}
for i = 1, 100 do
-- Create function to print our value
t[i] = function() print(i) end
-- Create function to increment value by one
t[-i] = function() i=i+1 end
end
t[1]() -- Prints 1
t[20]() -- Prints 20
t[-20]() -- Increment upvalue by one
t[20]() -- Now it is 21!
This example demonstrates one possible usage of upvalues and the fact that many functions can share them. This can be useful in a variety of situations together with the fact that upvalues can't be changed by side code (without use of debug library) and can be trusted in general.
I hope my answer covers what you wanted to know.
Note: Also, this language is called Lua, not LUA.
As a whole it doesn't have a name, no. There's lots of concepts that play into this:
First Class Functions aka. functions that can be assigned to variables and passed around just like numbers or strings.
Anonymous Functions aka. functions that are created without giving it a name explicitly. All functions in Lua are technically anonymous, but often they are assigned into a variable right after creation.
Metaprogramming aka. writing programs that write programs. A loop that creates functions (or methods) on an arbitrary number of objects is very simple, but I'd count it as metaprogramming.
Lua Tables; this may seem obvious, but consider that not all languages have a feature like this. Javascript has objects which are similar, but Ruby for example has no comparable feature.
If you're gonna use pairs, you might as well make use of both variables.
for key, object in pairs(D) do
function object:upAndWrite(self)
self:update()
print("upAndWrite was here")
end
end
Though that would create many closures, which means more work for the garbage collector, more memory usage and slower execution speed.
for key, object in pairs(D) do
print(object.upAndWrite) -- All the functions are different
end
It's a good first stage, but after refactoring it a bit you could get this:
do
local method = function(self) -- Create only one closure
self:update()
print("upAndWrite was here")
end
for key, object in pairs(D) do
object.upAndWrite = method -- Use single closure many times
end
end
Now there's only one closure that's shared among all the tables.
for key, object in pairs(D) do
print(object.upAndWrite) -- All the functions are the same
end
This is more of a design philosophy question as I already know you shouldn't call a function with : (object-oriented syntactic sugar) if the function has been defined without the self keyword by using .. But the problem is that programmers using a library I have created tend to not read the documentation and run into the question of "how should I call your function?", so I end up always defining functions using the method below:
local tbl = {};
function tbl:Add(a, b)
return a + b;
end
I have installed Luacheck (in VS Code) and it often complains when I use this syntax and not use the self referential keyword. It says: [luacheck] unused argument "self". Is there any problem with this in terms of performance (or is there a way of disabling Luacheck in VS Code)?
I prefer writing functions in this style as opposed to the style below:
function tbl.Add(_, a, b)
return a + b;
end
It seems a pain to have to add a dummy variable at the start of the parameter list.
EDIT: Another problem is what if you had many tables that implement a function with the same name and want to iterate over them but some implementations do not use the self argument and others do? It would be very tedious and bad design to check what type of table it is to call the function correctly.
What is the preferred style? A bit confused in general about this warning. What are your thoughts? Thanks.
if you're not using the self argument you can just do
function tbl.Add(a, b)
return a + b;
end
no need to use a dummy variable.
You just need to be sure then that you also call it with a . and not a :
so
local someValue = tbl.Add(1, 3)
for example and not
local someValue = tbl:Add(1, 3)
I'm trying to figure out a way to get all functions in a Lua script. This script has been compiled into a function through loadfile. For example, I'd want to get every function defined in the script below.
function example1()
end
local function example2()
end
local library = {}
function library:example3()
end
(function()
-- Functions like this too.
end)
The names aren't important, I'm just looking for a way to get the actual functions so I can use them in debug.getinfo and get information like the lines they were defined in. I have LuaJIT, if that makes this any easier. Is something like this even possible? Thanks in advance.
I guess the file declares its functions as global, or it would be really easy to track what is returned.
If that's the case, you can cycle through all the global items with a generic for loop, and only take the functions from them:
allFuncs = {}
for key, item in pairs(_G) do
if type(item) == "function" then
allFuncs[#allFuncs + 1] = item
end
end
(_G is the table holding all the global variables)
Then you will have a list (allFuncs) holding all the functions declared, but be aware that it will also contain default functions like setmetatable or xpcall.
It's easy to modify the code to not make this happen, but only use this for testing / learning:
function allFuncs()
local funcsTab = {}
for key, item in pairs(_G) do
if type(item) == "function" then
funcsTab[#funcsTab + 1] = item
end
end
return funcsTab
end
defaultFuncs = allFuncs()
--then you load your file: other functions get declared
--we create another table containg the default + the new functions
myFuncs = allFuncs()
--then you subtract the first table from the second
for i = 1, #myFuncs do
for o = 1, #defaultFuncs do
if myFuncs[i] == defaultFuncs[o] then
table.remove(myFuncs, i)
end
end
end
This is if your file doesn't return anything and declares its functions as globals.
If the file declares them as local and then returns a table containing them, just use the first piece of code replacing _G with that returned table.
This is not likely to be possible without syntax or bytecode analysis as each function definition is an assignment (just has different forms in your examples). See the bytecode inspector and a related discussion here. For the syntax analysis you can use metalua or something like lua-loose-parser. Keep in mind that even those tools won't give you the entire list of functions as some functions may be defined dynamically using loadstring (or similar methods).
If you only have access to the result of loadfile, then you best bet is to use the bytecode analyzer.
This is possible using jit.attach in LuaJIT.
You can attach callbacks to a number of compiler events with
jit.attach. The callback can be called:
when a function has been compiled to bytecode ("bc");
when trace recording starts or stops ("trace");
as a trace is being recorded ("record");
or when a trace exits through a side exit ("texit").
http://wiki.luajit.org/JIT-Compiler-API#jit-attach
jit.attach(function(f)
local funcInfo = jit.util.funcinfo(f)
end, "bc")
I have an object that I create using the following function
local function newObject(functionVariable)
...
functionVariable = functionVariable or nop
...
return setmetatable({
...
functionVariable = functionVariable,
...
}, Objectmt)
end
When I deepcopy this object using this
local function deepcopy(t)
if t == nil then return nil end
if type(t) == 'table' then
local copy = {}
for k, v in pairs(t) do
copy[k] = deepcopy(v)
end
setmetatable(copy, deepcopy(getmetatable(t)))
return copy
else -- number, string, boolean, etc
return t
end
end
and load in the object using this
for k, v in pairs(state.objectsTable) do objectsTable[k] = v end
the function variable is totally wrong. It isn't the function that was passed into the object anymore and yeilds unexpected results
There are a lot of things that could be going wrong, and not enough information to say for sure. However, there are some things I can see that could be wrong with your copy, and one in particular that seems problematic.
Your deepcopy function will copy the metatable of the object:
-- snip...
setmetatable(copy, deepcopy(getmetatable(t)))
-- ...
However, it is a fairly common practice for objects of the same type to share the same metatable, and moreover, your code seems to do this (although without seeing how Objectmt is defined, it isn't clear). Other code can then, for example, determine if something is an object by doing:
function isObject(obj)
return getmetatable(obj)==Objectmt
end
This will fail for your copy, because the metatable is no longer the same (even if it has the same contents).
This could be fixed by having a different version of deepcopy (or modifying the existing one) to reuse the metatable:
-- snip...
setmetatable(copy, getmetatable(t))
-- ...
If that is not the problem, then are are some other things to consider:
Your deepcopy function does not copy table keys. In some cases copying keys could be important, but that doesn't seem to be the case for any of the code you've shown.
Your deepcopy function will not copy functions. This could be important if you use functions with mutable upvalues. Again, this isn't the case for any of the code you've shown.
It is possible that there are other tables besides the metatable that ought to be copied by reference rather than by value. To know which is appropriate, you must understand the way they are used.
There could be userdata or other less common types (e.g. coroutines) that are currently being copied by reference that would need to be copied by value. Some things might not be copyable by value.
There might be something in the data you are copying that ought not by copied at all, for example, a unique identifier.
The problem might not be with the copy at all.
I'm going back to the basics here but in Lua, you can define a table like so:
myTable = {}
myTable [1] = 12
Printing the table reference itself brings back a pointer to it. To access its elements you need to specify an index (i.e. exactly like you would an array)
print(myTable ) --prints pointer
print(myTable[1]) --prints 12
Now functions are a different story. You can define and print a function like so:
myFunc = function() local x = 14 end --Defined function
print(myFunc) --Printed pointer to function
Is there a way to access the body of a defined function. I am trying to put together a small code visualizer and would like to 'seed' a given function with special functions/variables to allow a visualizer to 'hook' itself into the code, I would need to be able to redefine the function either from a variable or a string.
There is no way to get access to body source code of given function in plain Lua. Source code is thrown away after compilation to byte-code.
Note BTW that function may be defined in run-time with loadstring-like facility.
Partial solutions are possible — depending on what you actually want to achieve.
You may get source code position from the debug library — if debug library is enabled and debug symbols are not stripped from the bytecode. After that you may load actual source file and extract code from there.
You may decorate functions you're interested in manually with required metadata. Note that functions in Lua are valid table keys, so you may create a function-to-metadata table. You would want to make this table weak-keyed, so it would not prevent functions from being collected by GC.
If you would need a solution for analyzing Lua code, take a look at Metalua.
Check out Lua Introspective Facilities in the debugging library.
The main introspective function in the
debug library is the debug.getinfo
function. Its first parameter may be a
function or a stack level. When you
call debug.getinfo(foo) for some
function foo, you get a table with
some data about that function. The
table may have the following fields:
The field you would want is func I think.
Using the debug library is your only bet. Using that, you can get either the string (if the function is defined in a chunk that was loaded with 'loadstring') or the name of the file in which the function was defined; together with the line-numbers at which the function definition starts and ends. See the documentation.
Here at my current job we have patched Lua so that it even gives you the column numbers for the start and end of the function, so you can get the function source using that. The patch is not very difficult to reproduce, but I don't think I'll be allowed to post it here :-(
You could accomplish this by creating an environment for each function (see setfenv) and using global (versus local) variables. Variables created in the function would then appear in the environment table after the function is executed.
env = {}
myFunc = function() x = 14 end
setfenv(myFunc, env)
myFunc()
print(myFunc) -- prints pointer
print(env.x) -- prints 14
Alternatively, you could make use of the Debug Library:
> myFunc = function() local x = 14 ; debug.debug() end
> myFunc()
> lua_debug> _, x = debug.getlocal(3, 1)
> lua_debug> print(x) -- prints 14
It would probably be more useful to you to retrieve the local variables with a hook function instead of explicitly entering debug mode (i.e. adding the debug.debug() call)
There is also a Debug Interface in the Lua C API.