Lua : Function pass memory variable link instead of value - lua

Lua seems to pass parameters' memory adress to function instead of value
Is that a standard behaviour ?
Following code can be tested at https://www.lua.org/cgi-bin/demo
local t = {
Give = {"original"},
Etapes = {},
}
function check (obj)
for k, v in pairs(obj) do
if k == "Give" then
obj[k] = {"modified"}
end
end
-- return obj
end
print ("BEFORE t.Give[1]="..t.Give[1])
check(t)
print ("AFTER t.Give[1]="..t.Give[1])
print result :
BEFORE t.Give[1]=original
AFTER t.Give[1]=modified

Related

Lua: define functions from a table

NativeTable = {
["print"] = {},
["LoadResourceFile"] = {}
}
for k, v in pairs(NativeTable) do
k = function(...)
print("test")
end
end
this would result in defining them in the NativeTable and not as a global function
print = function(...)
print("test")
end
LoadResourceFile = function(...)
print("test")
end
So I'm trying to define a global function with a table name
Guess i could do smth like this
But there must be a better way?
NativeTable = {
["test"] = {},
["LoadResourceFile"] = {}
}
local function OverWriteFunction(FuncName, Func)
local Base = [[ = function(...)
print("jaa")
end
]]
local Final = FuncName .. Base
return Final
end
for k, v in pairs(NativeTable) do
load(OverWriteFunction(k))()
end
In your first example you are redefining the variable k, that is local inside the for loop, so this will not be usable outside the one loop where you define it.
Your second example is something you absolutely should avoid if you can, since defining code inside a string and loading it later means, that even only a syntax error will not be shown on "compiling" it, but only when that exact part is executed. And especially, when you are concatenating string that are meant to be code, you just get the risk of glueing something together wrongly, if you try to have that made generically.
If I understood correctly what you are trying to achieve, I would say, it could be something like this:
NativeTable = {
["test"] = {},
["LoadResourceFile"] = {},
[3] = {}
}
for k, v in pairs(NativeTable) do
if type(k) == "string" then
_G[k] = function(...)
print("output")
end
end
end
test()
LoadResourceFile()
-- _G[3]()
Which outputs:
output
output
What I have done here is to use the _G table which is the global environment of lua, all things you define there with a string in the brackets will be globally available (and what is globally available is inside that table, so be careful, since you can override other functions and variables you have defined!), even when writing it as a normal function call. I did also make sure, to only do this, when the type of k was string, otherwise you could start to define functions that can be called like the last commented out call.
This doesn't make too much sense for me:
NativeTable = {
["print"] = {},
["LoadResourceFile"] = {}
}
for k, v in pairs(NativeTable) do
k = function(...)
print("test")
end
end
First you create a table with table elements print and LoadResourceFile.
Then you iterate over that table and replace the table elements with functions.
Why not simply do this:
myTable = {
a = function() print("I'm function a") end,
b = function() print("I'm function b") end,
}
or
myTable = {}
myTable.a = function () print("I'm function a") end
Then you can call the global function like so: myTable.a()
If you insist on having those functions outside of a table you can simply insert them into the global environment table.
for k, v in pairs(myTable) do _G[k] = v end
then you could call a and b globally. But whatever you're trying to accomplish there's probably a better way than this.

Get Reference to Calling Function in Lua

I know I can use debug.getinfo(1, "n").name to get the calling function's name, but I would like to get a reference to that function pointer itself.
For debug.getlocal(), the f parameter is the stack position so I can easily get the locals for the calling function by just choosing the correct index. But for debug.getupvalue(), the f parameter is the function pointer itself, which I don't have.
Here is a brief example, but with the offending line debug.getupvalue(someFunction, index) there to demonstrate what I would like to accomplish, without the hard-coded reference.
local someUpValue = "stackoverflow"
function someFunction()
local value1 = "hi"
local value2 = "there"
local value3 = someUpValue
log()
end
function log()
local callingFuncName = debug.getinfo(2, "n").name
local index = 1
while(true) do
local name, value = debug.getlocal(2, index)
if name then
print(string.format("Local of %s: Name: %s Value: %s", callingFuncName, name, value))
else
break
end
index = index + 1
end
index = 1
while(true) do
local name, value = debug.getupvalue(someFunction, index)
if name then
print(string.format("Upvalue of %s: Name: %s Value: %s", callingFuncName, name, value))
else
break
end
index = index + 1
end
end
someFunction()
You can use debug.getinfo(2, "f").func to get the function reference (assuming you are calling from the function you want to get a reference to):
function log()
local callingFuncRef = debug.getinfo(2, "f").func
callingFuncRef(false) -- this will call the function, so make sure there is no loop

Accessing the key in the value (right side) of a table key affectation in Lua

The goal is to match a key of a table with a value depending of the key.
example = { ["dummy"] = this .. " example" }
print example.dummy -- print "dummy example"
Where this is the keyword to refer to the key. Is there any way to do that in Lua?
There is no way to do this directly.
You could do some preprocessing:
example = { ["dummy"] = "{THIS} example" }
for k,v in pairs(example) do
example[k]=v:gsub("{THIS}",k)
end
print(example.dummy)
It's not possible to have as clean an expression as:
t = { foo = this .. ' bar' }
because this would always be expressed without relation to the key or the table. That is, you can't capture an expression as the value of a table entry.
What is possible is implementing some level of indirection using metatables and functions, but it's hardly pretty. Here we do fetch-time evaluation. You could also recompute the results.
local function indirect_table ()
local uptable = {}
return setmetatable({}, {
__index = function (self, key)
local value = uptable[key]
return type(value) == 'function' and uptable[key](key) or value
end,
__newindex = function (self, key, value)
uptable[key] = value
--[[precompute, with no need for an uptable, or __index:
`rawset(self, key, value(key)`]]
end
})
end
local tab = indirect_table()
tab.foo = function (key) return key .. 'bar' end
print(tab.foo) --> 'foobar'
Note: this example uses a closure, but you can implement this kind of pattern using getmetatable as well.
Personally, I'd abstract this into an indirection pattern that allows arbitrary keys and values, and their actions to be specified. I figure this kind of pattern would mostly be used programatically, rather than by hand, where the results of key values are dependent on the inputs received. Again, not pretty, but a little more robust (optional actions).
local function I (_, value) return value end
local K = setmetatable({
__call = function (actor, key)
return actor.action(key, actor.value)
end
}, {
__call = function (K, value, action)
return setmetatable({ value = value, action = action or I }, K)
end
})
local T = setmetatable({
__newindex = function (self, key, value)
if getmetatable(value) == K then
value = value(key)
end
rawset(self, key, value)
end
}, {
__call = function (T, o)
return setmetatable(o or {}, T)
end
})
Simple use:
local function concat (left, right) return left .. right end
local t = T {}
t.foo = K('bar', concat) -- with a common action
t.zar = K({}, unknown_action) -- without action (`nil`)
t.qux = 'qaz' -- standard
print(t.foo, t.zar, t.qux)
This is strange metaprogramming. I'd double-check the reasoning for needing such an approach. Perhaps you're falling into an XY Problem trap? Really feels like a solution to a problem that doesn't need to exist in the first place.

quoting troubles in Lua

I am trying to make a quote function in lua, so i can use the arguments as strings but without quotes or access them in some environment. Much like in the second comment on this question
w = print
function test()
local function _ix( _ , k )
w( " _ix \\ " , _ , k )
local v = rawget( _G , k )
w( " <-- " , k )
return k
end
local _ = setmetatable( {} , { __index = _ix } )
local function q( _ ) return _ end
q = setfenv( q , _ )
return q
end
So, when I run it:
q = test()
w( "q( uno )" , q( uno ) )
It doesn't even call the __index metamethod:
---------- Capture Output ----------
q( uno ) nil
> Terminated with exit code 0.
So, what I'm doing wrong?
If I'm understanding correctly, then what you're trying to do doesn't make much sense. uno will be looked up in the environment that q is called in, not with. In your example it's like calling q(nil). The example from the other question works because they're working in the same, global environment.
You can use write a helper function to intercept your current environments nil-lookups, but it must be called preemptively in any environment you want to use these nil-to-string lookups.
local function intercept (tab)
setfenv(2, setmetatable(tab or {}, {
__index = function (_, key)
return key
end
}))
end
And you'll need an environment cloning function, unless you want to manually create your sandboxes every time, else you'll probably mess up parent environments (e.g., _G). You could move this logic inside of intercept for a cleaner function call, but with less flexibility.
local function clone_current_env ()
local env = {}
for key, value in pairs(getfenv(2)) do
env[key] = value
end
return env
end
Using them together, you can cause nil lookups in whichever environment you're in to become strings.
intercept(clone_current_env())
print(type(foo), type(bar)) --> string string
This is some ugly metaprogramming, and I don't really know why you'd want to write code like this, except as a proof of concept.
A full example.
DEMO
local function clone (tab)
local new = {}
for key, value in pairs(tab) do
new[key] = value
end
return new
end
local function enable_nil_strings ()
setfenv(2, setmetatable(clone(getfenv(2)), {
__index = function (env, key)
return key
end
}))
end
local function disable_nil_strings()
setmetatable(getfenv(2), nil)
end
-----------------------------------------------------
print(type(foo), type(bar)) --> nil nil
enable_nil_strings()
print(type(foo), type(bar)) --> string string
disable_nil_strings()
print(type(foo), type(bar)) --> nil nil
Finally, arguably the best way to implement this would be to simply wrap around an execution context:
local function with_nil_strings (context, ...)
local env = {}
for key, value in pairs(getfenv(2)) do
env[key] = value
end
setfenv(
context,
setmetatable(env, {
__index = function (_, key) return key end
})
)
context(...)
end
print(type(foo)) --> nil
with_nil_strings(function ()
print(type(foo)) --> string
end)
print(type(foo)) --> nil

Weird "attempt call field "drawers"(a table value)" error

I was working on this project about a year ago. I came back to it and now it throws an error when I run it the error is "attempt call field "drawers"(a table value)".
This is where the drawers field is
local Renderer = {}
local num_of_layers = 2
local insert = table.insert
local remove = table.remove
function Renderer:create()
local render = {}
render.drawers = {}
for i = 0, num_of_layers do
render.drawers[i] = {}
end
function render:addRenderer(obj, layer)
local l = layer or 0
insert(self.drawers(l), i, obj)
end
return render
end
return Renderer
This is where it is being called
local tlm = {}
function tlm:load()
renderer:addRenderer(self)
gameloop:addLoop(self)
end
This is not correct:
insert(self.drawers(l), obj)
self.drawers is not a function but a table. therefor a function call like self.drawers(1) results in an error.
If you wanted to insert an element to the table self.drawers at index l using Luas standard functions you should call:
table.insert(self.drawers, i, obj)
If you want to replace the value at index l you can simply write self.drawers[l] = obj
http://www.lua.org/manual/5.3/manual.html#pdf-table.insert

Resources