Metamethod lookup through __index? - lua

I've implemented my own class system and I'm having trouble with __tostring; I suspect a similar issue can happen with other metamethods, but I haven't tried.
(Brief detour: each class has a __classDict attribute, holding all methods. It is used as the class instances' __index. At the same time, the __classDict's __index is the superclass' __classDict, so methods in superclasses are authomatically looked up.)
I wanted to have a "default tostring" behavior in all instances. But it didn't work: the "tostring" behavior doesn't "propagate" through subclasses correctly.
I've done this test exemplifying my issue:
mt1 = {__tostring=function(x) return x.name or "no name" end }
mt2 = {}
setmetatable(mt2, {__index=mt1})
x = {name='x'}
y = {name='y'}
setmetatable(x, mt1)
setmetatable(y, mt2)
print(x) -- prints "x"
print(mt2.__tostring(y)) -- prints "y"
print(y) -- prints "table: 0x9e84c18" !!
I'd rather have that last line print "y".
Lua's "to_String" behaviour must be using the equivalent of
rawget(instance.class.__classDict, '__tostring')
instead of doing the equivalent of
instance.class.__classDict.__tostring
I suspect the same happens with all metamethods; rawget-equivalent operations are used.
I guess one thing I could do is copying all the metamethods when I do my subclassing (the equivalent on the above example would be doing mt2.__tostring = mt1.__tostring) but that is kind of inelegant.
Has anyone fought with this kind of issue? What where your solutions?

I suspect the same happens with all metamethods; rawget-equivalent operations are used.
That is correct.
from the lua manual:
... should be read as rawget(getmetatable(obj) or {}, event). That is, the access to a metamethod does not invoke other metamethods, and the access to objects with no metatables does not fail (it simply results in nil).
Generally each class has its own metatable, and you copy all references to functions into it.
That is, do mt2.__tostring = mt1.__tosting

Thanks to daurnimator's comments, I think I found a way to make metamethods "follow" __index as I want them to. It's condensed on this function:
local metamethods = {
'__add', '__sub', '__mul', '__div', '__mod', '__pow', '__unm', '__concat',
'__len', '__eq', '__lt', '__le', '__call', '__gc', '__tostring', '__newindex'
}
function setindirectmetatable(t, mt)
for _,m in ipairs(metamethods) do
rawset(mt, m, rawget(mt,m) or function(...)
local supermt = getmetatable(mt) or {}
local index = supermt.__index
if(type(index)=='function') then return index(t,m)(...) end
if(type(index)=='table') then return index[m](...) end
return nil
end)
end
return setmetatable(t, mt)
end
I hope it is straightforward enough. When a new metatable is set, it initializes it with all metamethods (without replacing existing ones). These metamethods are prepared to "pass on" requests to "parent metatables".
This is the simplest solution I could find. Well, I actually found a solution that used less characters and was a bit faster, but it involved black magic (it involved metatable functions de-referencing themselves inside their own bodies) and it was much less readable than this one.
If anyone finds a shorter, simpler function that does the same, I'll gladly give him the answer.
Usage is simple: replace setmetatable by setindirectmetatable when you want it to "go up":
mt1 = {__tostring=function(x) return x.name or "no name" end }
mt2 = {}
setmetatable(mt2, {__index=mt1})
x = {name='x'}
y = {name='y'}
setmetatable(x, mt1)
setindirectmetatable(y, mt2) -- only change in code
print(x) -- prints "x"
print(mt2.__tostring(y)) -- prints "y"
print(y) -- prints "y"
A little word of warning: setindirectmetatable creates metamethods on mt2. Changing that behavior so a copy is made, and mt2 remains unaltered, should be trivial. But letting them set up by default is actually better for my purposes.

From my experience with Lua 5.1, metamethods are looked up in metatables using rawget(), and that's why you must copy the reference to the function into every class table you create.

See the Inheritance Tutorial on the Lua Users Wiki.

Related

how is a function navigating through fields of a table

i already asked this question on stackoverflow and accepted an answer i think i did not really understand the answer and i got some more question, im embarrassed to necro it so im creating a new question
im learning lua and got to metatable part, in this example
local tb = {}
local meta = {}
function tb.new(s)
local super = {}
super.s = s
setmetatable(super,meta)
return super
end
function tb.add(s1,s2)
return s1.s..s2.s
end
meta.__add = tb.add
f= tb.new("W")
t= tb.new("E")
print(f+t)
when compiler gets tof = tb.new("W")
i think this happens
function tb.new("W") super.W = W return setmetatable(super,meta) return super end
so
print(f+t)
looks like
print(super+super)
how does
tb.add(super,super)
find the fields of super table using
return s1.s..s2.s
also as the
tb.new
function is called twice and
setmetatable(super,meta)
happens twice is there any difference between the first and second iteration? if any of the above are incorrect please correct me.
when compiler gets tof = tb.new("W") i think this happens function tb.new("W") super.W = W return setmetatable(super,meta) return super end
No. It's more like super['s'] = 'W'. That's how dot notation works. I hope that clarifies how Lua "finds the fields" later.
as the tb.new function is called twice and setmetatable(super,meta) happens twice is there any difference between the first and second iteration?
They're different, because the super variable is a new table each time. Any time you see {} (a table constructor), whether empty or not, it's creating an entirely new table. meta, however, is still the same table, because it only gets a table constructor once, outside of any function.

Adding labels to my programming language

Actually I am writting a programming language in Lua. It was quite fun. I've wrote a bit of standard library (stack op and simple io). Then I've thought about labels. It would look like in assembly. While and for loop aren't funny in any bit so programming in that language can be quite challenging. Here are some requirements for this system:
Label stack (or array, dictionary) must be accessible from global context.
Jump instruction handler will be in separate file.
This is how my label-handling function look like:
function handleLabel(name,currentLine)
end
I have no idea how to implement this kind of magic. First I've thought about that:
LabelLineIDS = {}
Labels = {}
Labelamount = 1;
function handleLabel(name,currentLine)
LabelLineIDS[Labelamount]=currentline
Labels[Labelamount]=name
Labelamount=Labelamount+1
end
-- In file "jump.lua":
local function has_value (tab, val)
for index, value in ipairs(tab) do
if value == val then
return index
end
end
print ("Error: Label not defined.") -- Bail out.
os.exit(1)
end
local function _onlabel()
local labelName = globalparams --Globalparams variable contain parameters to each function, at the moment
--this will contain label name. It _can_ be nil.
return LabelLineIDS[has_value(Labels, labelName)]
end
CurrLine = _onlabel() --Currline - current line that get's parsed.
--1 command per one line.
But I'm unsure is this well written or even work. Can you give me idea how to parse labels in my programming language (and write jump functions)? Or if my code is pretty ok at the moment, can you help me to improve it?
Using line counter in my parser I've decided to implement gotos like we can see in BASIC. Thanks everyone for help.

I need clarification on Metatable.__index

I asked earlier why my methods for a metatable weren't being located by Lua, and was told that by setting __index to my metatable, that it would resolve the issue, so I assumed that a method when called was searching by index in the metatable, but I've ran into an issue now that I need to use indexing brackets [ and ] on my metatable, so __indexis assigned to return an index from a table inside of it, how do I resolve the functionality needs of both using methods, and use of indexing brackets
I wrote a minimal example indicating the problem:
TestMetatable = {DataTable = {}}
TestMetatable.__index = TestMetatable
function TestMetatable.new()
local Tmp = {}
setmetatable(Tmp,TestMetatable)
Tmp.DataTable = {1}
return Tmp
end
function TestMetatable:TestMethod()
print("Ran Successfully")
end
function TestMetatable.__index(self,index)
return self.DataTable[index]
end
local Test = TestMetatable.new()
-- both functionalities are needed
print(Test[1])
Test:TestMethod()
You need to understand the difference between __index and __newindex, and their relationship with the current contents of the main table.
__newindex is only called/accessed when all the following are true:
When you are setting a value into the main table, via tbl[index] = expr (or equivalent syntax, like tbl.name = expr).
When the key you are trying to set into the main table does not already exist in the main table.
The second one trips people up often. And that's your problem here, because __index is only accessed when:
When the key being read from the main table does not already exist in the main table.
So if you want to filter every read from and write to a table, then that table must always be empty. Therefore, those reads and writes need to go into some other table you create for each new object. So your new function needs to create two tables: one that remains empty and one that has all the data in it.
Honestly, I wish Lua had a way to create just an empty piece of userdata that you could bind a user-defined metatable to, just to avoid these issues.
the way I resolved this problem, according to Nicol Bolas's solution, if it might give clarity to anyone else's confusion :-)
TestMetatable = {DataTable = {}, FunctionTable = {}}
function TestMetatable.new()
local Tmp = {}
setmetatable(Tmp,TestMetatable)
Tmp.DataTable = {1}
Tmp.FunctionTable = TestMetatable
return Tmp
end
function TestMetatable:TestMethod()
print("Ran Successfully")
end
function TestMetatable.__index(self,index)
if type(index) == "string" then
return self.FunctionTable[index]
else
return self.DataTable[index]
end
end
local Test = TestMetatable.new()
-- both functionalities are needed
print(Test[1])
Test:TestMethod()

How to set name for function which is in the table

For example, I have a table
table.insert( t, 1, function()
print ("rock");
end );
Is there any way to get function name from this table. I know that I can store name like a key, but what if I want to keep numeric index and also I want to know function name?
Is there any way to do it?
Thanks, on advance.
Say you have this code:
t = {}
x = 5
table.insert(t, 1, x)
t would then be {[1] = 5}. "5" is just a number - it has no name, and isn't associated with the variable "x"; it's a value.
In Lua, functions are treated exactly the same way, as values:
t = {}
x = function() print("test! :D") end
table.insert(t, 1, x)
The value of x is not associated with x in any way, shape, or form. If you want to manually name a function, you can do it by wrapping the function in a table, for example:
t = {}
x = function() print("test! :D") end
table.insert(t, 1, {
name = "MyFunctionName",
func = x
})
That is how you would do it!
...unless..
..you break the rules!
When Lua was developed, the developers realised that the anonymous nature of functions would make productive error messages difficult to produce, if not impossible.
The best thing you'd see would be:
stdin: some error!
stdin: in function 'unknown'
stdin: in function 'unknown'
So, they made it so that when Lua code was parsed, it would record some debug information, to make life easier. To access this information from Lua itself, the debug library is provided.
Be very careful with functions in this library.
You should exert care when using this library. The functions provided here should be used exclusively for debugging and similar tasks, such as profiling. Please resist the temptation to use them as a usual programming tool: they can be very slow. Moreover, several of these functions violate some assumptions about Lua code (e.g., that variables local to a function cannot be accessed from outside or that userdata metatables cannot be changed by Lua code) and therefore can compromise otherwise secure code.
To achieve your desired effect, you must use the debug.getinfo function; an example:
x = function()
print("test!")
print(debug.getinfo(1, "n").name)
end
x() -- prints "test!" followed by "x"
Unfortunately, the form of debug.getinfo that operates directly on a function doesn't fill the name argument (debug.getinfo(x, "n").name == nil) and the version above requires you to run the function.
It seems hopeless!
...unless..
..you really break the rules.
The debug.sethook function allows you to interrupt running Lua code at certain events, and even change things while it's all happening. This, combined with coroutines, allows you to do some interestingly hacky stuff.
Here is an implementation of debug.getfuncname:
function debug.getfuncname(f)
--[[If name found, returns
name source line
If name not found, returns
nil source line
If error, returns
nil nil error
]]
if type(f) == "function" then
local info = debug.getinfo(f, "S")
if not info or not info.what then
return nil, nil, "Invalid function"
elseif info.what == "C" then
-- cannot be called on C functions, as they would execute!
return nil, nil, "C function"
end
--[[Deep magic, look away!]]
local co = coroutine.create(f)
local name, source, linedefined
debug.sethook(co, function(event, line)
local info = debug.getinfo(2, "Sn")
name = info.namewhat ~= "" and info.name or nil
source, linedefined = info.short_src, info.linedefined
coroutine.yield() -- prevent function from executing code
end, "c")
coroutine.resume(co)
return name, source, linedefined
end
return nil, nil, "Not a function"
end
Example usage:
function test()
print("If this prints, stuff went really wrong!")
end
print("Name = ", debug.getfuncname(test))
This function isn't very reliable - it works sometimes, and doesn't others. The debug library is very touchy, so it's to be expected.
Note that you should never use this for actual release code! Only for debugging!
The most extreme case that is still acceptable is logging errors on piece of released software, to help the developer fix issues. No vital code should depend on functions from the debug library.
Good luck!
The function hasn't got any name. If you want you can assign it to a named variable:
theFunction = t[1]
-- Call it:
theFunction()
If what you want is storing a named function to the table, define it beforehand and use its name to store it:
theFunction = function()
print ("rock");
end
table.insert(t, 1, theFunction)
If this is not what you meant, give more details; for example how you would like to access the function. You're question is a bit misty.
The thing is table.insert considers the table as a sequence, only with numeric keys.
If you want to be able to call the function as t.fun() you'll have to use the table as an associative array and hence use a string as key. (BTW any type except nil or NaN are allowed as key)
t={}
t['MyFun']=function print'foo' end
t.myFun() -- uses syntactic sugar for string keys that are valid identifiers.
You might also notice that functions are passed by reference. So all functions are actually anonymous, and are just stored as a value to a certain key or variable.
You can store the names in a separate table.
functions = {}
functionNames = {}
function addFunction(f, name)
table.insert(functions, f)
functionNames[name] = f
end
To get the function, you can use the index. Once you have the function, you can get its name from function_names:
f = functions[3]
name = functionNames[f]
Good luck!

lua - get the list of parameter names of a function, from outside the function

I'm generating some (non-html) documentation for a Lua library that I developed. I will generate the documentation by hand, but I'd appreciate some kind of automation if possible (i.e. generating skeletons for each function so I can fill them in)
I'd like to know if there's a way for lua to know the names of the parameters that a function takes, from outside it.
For example, is there a way to do this in Lua?
function foo(x,y)
... -- any code here
end
print( something ... foo ... something)
-- expected output: "x", "y"
Thanks a lot.
ok,here is the core code:
function getArgs(fun)
local args = {}
local hook = debug.gethook()
local argHook = function( ... )
local info = debug.getinfo(3)
if 'pcall' ~= info.name then return end
for i = 1, math.huge do
local name, value = debug.getlocal(2, i)
if '(*temporary)' == name then
debug.sethook(hook)
error('')
return
end
table.insert(args,name)
end
end
debug.sethook(argHook, "c")
pcall(fun)
return args
end
and you can use like this:
print(getArgs(fun))
Try my bytecode inspector library. In Lua 5.2 you'll be able to use debug.getlocal.
Take a look at debug.getinfo, but you probably need a parser for this task. I don't know of any way to fetch the parameters of a function from within Lua without actually running the function and inspecting its environment table (see debug.debug and debug.getlocal).
function GetArgs(func)
local args = {}
for i = 1, debug.getinfo(func).nparams, 1 do
table.insert(args, debug.getlocal(func, i));
end
return args;
end
function a(bc, de, fg)
end
for k, v in pairs(GetArgs(a)) do
print(k, v)
end
will print
1 bc
2 de
3 fg
Basically we use debug.getinfo to retrieve the nparams attribute (which gives us the information of how many parameters the function takes) and debug.getlocal to access the name of the parameters.
Tested and working with Lua 5.4
Take a look at the luadoc utility. It is sort of like Doxygen, but for Lua. It is intended to allow the documentation to be written in-line with the source code, but it could certainly be used to produce a template of the documentation structure to be fleshed out separately. Of course, the template mechanism will leave you with a maintenance issue down the road...

Resources