Get Reference to Calling Function in Lua - 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

Related

Lua : Function pass memory variable link instead of value

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

Lua function getting different datatype when given a number

I have this problem in a Lua class. Here is the code of my class:
local Temp = {}
function Temp:new(tmp)
local self = {temp = -273.15}
if tmp > self.temp then
self.temp = tmp
end
local setC = function(usrTmp)
if usrTmp < -273.15 then
self.temp = -273.15
else
self.temp = usrTmp
end
end
local getC = function()
return self.temp
end
local getF = function()
return self.temp * 1.8 + 32
end
local getK = function()
return self.temp + 273.15
end
return {
setC = setC,
getC = getC,
getF = getF,
getK = getK
}
end
return Temp
And here is my main method:
temp = require "tempClass"
io.write("Please enter the initial temperature: ")
usrTemp = io.read("*n")
myTemp = temp:new(usrTemp)
print("The current temperature in Celsius is: ".. myTemp:getC())
print("The current temperature in Fahrenheit is: " .. myTemp:getF())
print("The current temperature in Kelvin is: " .. myTemp:getK())
io.write("Please enter new temperature: ")
changeTemp = io.read("*n")
myTemp:setC(changeTemp)
print("The current temperature in Celsius is: " .. myTemp:getC())
print("The current temperature in Fahrenheit is: " .. myTemp:getF())
print("The current temperature in Kelvin is: " .. myTemp:getK())
io.write("Please enter new temperature: ")
My problem is the if usrTmp < -273.15 then line in the setC function. I'm getting this error message:
lua: ./tempClass.lua:10: attempt to compare table with number
stack traceback:
./tempClass.lua:10: in function 'setC'
[string "<eval>"]:14: in main chunk
I know, however, that usrTmp is a number. If I call type on the variable before the function, I get type number. In the function, the type is table. Why is usrTmp a table in the function? How can I fix this? Thanks!
You need to be explicit about the self parameter when defining functions that shall be used with it. The function setC should have an additional such parameter:
local setC = function(self, usrTmp)
-- as before...
end
Recall that these two invocations are identical:
myTemp:setC(changeTemp)
myTemp.setC(myTemp, changeTemp)
That should explain the actual error message your received.
In addition, you need to turn Table.new into an ordinary (not self-parameter-enhanced) function. It's not connected to an instance yet, it is supposed to return one. And finally, the state variable temp must be included in the table that Table.new returns:
function Temp.new(tmp)
-- ^ note the dot instead of the colon
-- function body as before, but all functions now need the self parameter, e.g.:
local getC = function(self)
return self.temp
end
return {
temp = self.temp,
setC = setC,
getC = getC,
getF = getF,
getK = getK
}
end

Changing variable in a table

How can I make a changing variable an element of a table, like so.
local table = {}
local var = 10
Now I want to insert this variable as an element of table.
Something like this:
table[1] = var
What I need is, whenever I call this table[1], even if the variable changes, it will call the actual value of that variable, like this:
print(table[1]) -> prints 10
var = var + 5
print(table[1]) -> prints 15
Is this even possible somehow?
EDIT:
What I want to accomplish is the following: I want to have an element in table that says which variable should be shown. For example:
local var1 = 10
local var2 = 20
Now if I have a table that has elements as strings of those variables like so:
local table = {"var1", "var2"}
Now if I do print(table[1]), of course it will print out "var1", but is there any way I could turn this element of a table that is string into a call for variable when I actually need that variable. You might be asking why don't I just call the var1, but there is a reason which I can explain, but it would be really long. Let's say I just need it this way. Also, the var1/var2 CAN CHANGE.
You have a couple of choices.
1) Field function as a closure over var: Straightforward but requires changes how you use it
local t = {}
local var = 10
t.varf = function() return var end -- varf could be named var but that might be confusing
var = var + 5
print(t.varf()) -- call it to get the value
2) __index metamethod to avoid the explicit function call syntax
local t = {}
local var = 10
setmetatable(t, {
__index = function(_, k)
if k=="var" then return var else return nil
end})
var = var + 5
print(t.var) -- t does not contain a field with key "var" so __index is called
(The __index function is also a closure over var.)
If you want to modify var via t, then look to the __newindex metamethod.
Both methods use closures. A closure is a function that refers to non-global variables outside of its parameters and body.
Numbers in Lua are shared by copy, at time of assignment. The table[1] and var both receive their own, independent copy of the number 10.
If you want to share numbers, you'll need to encapsulate them in their own table.
local table = {}
local var = { value = 10 }
table[1] = var
print(table[1].value) -- prints 10
var.value = var.value + 5
print(table[1].value) -- prints 15
You can also consider creating some kind of abstraction over numbers. A quick example. You'll need to make sure your operations are well defined, though.
local number = {}
number.__index = number
local function Number (value)
return setmetatable({ value = value }, number)
end
function number.__add (a, b)
if type(b) == 'number' then
return Number(a.value + b)
elseif getmetatable(b) == number then
return Number(a.value + b.value)
end
error("one of `number, Number' expected")
end
function number:add (n)
if type(n) == 'number' then
self.value = self.value + n
elseif getmetatable(n) == number then
self.value = self.value + n.value
else
error("one of `number, Number' expected")
end
return self.value
end
function number.__tostring (v)
return v.value .. ''
end
local foo = {}
local bar = Number(10)
foo[1] = bar
print(foo[1]) -- 10
bar:add(5)
print(foo[1]) -- 15
print(bar + 25) -- 40

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

Referencing functions enclosing table in Lua

I have a helper function which returns a table like this:
function of_type(expected_type)
return {
expected = expected_type,
matches = function(value) return type(value) == expected_type end,
describe = "type " .. expected_type
}
end
Now this was fine with other matchers but here I would like to store the type(value) to a field in the same table when the matches function is called. Something like this:
function of_type(expected_type)
return {
expected = expected_type,
mismatch = nil, -- set it to nil on initialization
matches = function(value)
mismatch = type(value) -- how to do this?
return type(value) == expected_type
end,
describe = "type " .. expected_type
}
end
Is this possible?
Yes, but you need to split it into steps:
function of_type(expected_type)
local tbl = {
expected = expected_type,
mismatch = nil, -- set it to nil on initialization
describe = "type " .. expected_type
}
tbl.matches = function(value)
tbl.mismatch = type(value)
return type(value) == tbl.expected
end
return tbl
end
-- testing it
local foo = of_type("string")
print(foo.matches(1), foo.matches("1"))
This should output false true as you would expect.
Essentially, tbl.matches will store the reference to tbl (it's called "upvalue") and will be able to modify all the fields in that table (including the reference to itself it in).
Another way to do this would be the following (notice the changes in the tbl.matches function). Instead of capturing it as an upvalue, you can use tbl:method semantic and pass tbl as implicit self parameter:
function of_type(expected_type)
local tbl = {
expected = expected_type,
mismatch = nil, -- set it to nil on initialization
describe = "type " .. expected_type
}
function tbl:matches(value)
self.mismatch = type(value) -- how to do this?
return type(value) == self.expected
end
return tbl
end
local foo = of_type("string")
print(foo:matches(1), foo:matches("1"))
This will print the same result. Notice that you are using foo:matches notation to make foo to be passed as the first parameter (references as self in the method). This is the same as using foo.matches(foo, 1).
You don't. Well, not without storing a copy of the table, or passing the function the table as a parameter. Until all of the statements of the table constructor have been processed, the table doesn't exist yet. And since you never stored it anywhere (in this function), your function can't name it in order to find it.
So you should give it a name, even just for a moment:
function of_type(expected_type)
local temp = nil
temp = {
expected = expected_type,
mismatch = nil, -- set it to nil on initialization
matches = function(value)
temp.mismatch = type(value) -- Like this
return type(value) == expected_type
end,
describe = "type " .. expected_type
}
return temp
end
This works because Lua will store temp as an upvalue. Thus, the function you're creating will see changes in temp, such as when you set it to a table value. And since it's a local variable, it won't be visible outside of this function.

Resources