Metatable is not indexed, even though setmetatable is used - lua

According to the Lua manual, setmetatable still works the same as in Lua 5.0. Yet for some reason, when I try this code in Lua 5.1.5 and 5.3.1, it appears that the metatable is not accessed:
ClassTable = {}
ClassTable.getString = function(self)
return self.x .. ""
end
inst = {}
setmetatable(inst, ClassTable)
inst.x = 7
--doens't work
assert(getmetatable(inst) == ClassTable)
print(inst:getString())
The first case works, however in the second case the I get the error which suggests that the metatable is not being used:
./lua: /test.lua:12: attempt to call method 'getString' (a nil value)
stack traceback:
test.lua:12: in main chunk
[C]: ?
This also has nothing to do with the method call operator ":" as even getting the value of the method doesn't go to the metatable.
print(inst.getString)
nil

To make the table inst access the metatable you need to use the metamethod __index.
So you can correct the code by adding this line at the top below ClassTable.getString definition:
ClassTable.__index = ClassTable
Despite the name, the __index metamethod does
not need to be a function: It can be a table, instead. When it is a
function, Lua calls it with the table and the absent key as its
arguments. When it is a table, Lua redoes the access in that table.
http://www.lua.org/pil/13.4.1.html

Related

passing parameters of a function to another function when using metatable

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)
in this part
function tb.add(s1,s2)
return s1.s..s2.s
end
how are values from super.s passed to tb.add function. i noticed that the variable s in s1.s and s2.s in return s1.s..s2.s seems to be the link between tb.new and tb.add.
and in this part
f= tb.new("W")
t= tb.new("E")
print(f+t)
when compiler gets to f+t i think this function is called first f= tb.new("W") in this function right now there is no s2 so it should be nil how did return s1.s..s2.s happen?
Your code is missing a table tb. Otherwise it results in an error for indexing a nil value.
Your code creates two table values with a field s = "E" and s = "W" respectively. Both have share the same metatable meta that implements the __add metamethod.
From the Lua 5.4 Reference Manuual 2.4 - Metatables and Metamethods
Every value in Lua can have a metatable. This metatable is an ordinary
Lua table that defines the behavior of the original value under
certain events. You can change several aspects of the behavior of a
value by setting specific fields in its metatable. For instance, when
a non-numeric value is the operand of an addition, Lua checks for a
function in the field __add of the value's metatable. If it finds one,
Lua calls this function to perform the addition.
So for f+t will call meta._add(f, t) which returns f.s..t.s
tb.new basically just creates a new table and returns it, so in this code:
f= tb.new("W")
t= tb.new("E")
... f and t are newly created tables, each with an s field and both with the same metatable.
The interpreter automatically calls meta.__add when it sees f+t and passes both operands as arguments. tb.add has two parameters and assumes both of them have an s field which is a string, so that all checks out perfectly. If t was not a table with an s field, then you would be in trouble.
In other words, tb.new does not pass s to tb.add. tb.new stores s inside the new table, and tb.add retrieves that value from its parameters.
As commented by #lhf and answered by #Piglet the code is not working as is.
So here is a corrected version that uses/show new Lua 5.4 warn().
It can be used for debugging because #on and #off let you control the output.
Here it is...
if warn==nil then warn=print else warn('#on') end
local meta={}
local tb={}
function tb.new(s)
warn('tb.new("'..s..'")')
local super={}
super.s=s
setmetatable(super,meta)
return super
end
function tb.add(s1,s2)
warn('__add('..tostring(s1)..', '..tostring(s2)..')')
return s1.s..s2.s
end
meta.__add=tb.add
f=tb.new("W")
t=tb.new("E")
print('Print: ',f+t)
Output is...
Lua warning: tb.new("W")
Lua warning: tb.new("E")
Lua warning: __add(table: 0x5661f510, table: 0x5661f580)
Print: WE
( On earlier Lua versions than 5.4 print() is used instead of warn() )

How do I get rid of the "The metatable is locked" thingy on Lua? And how do I add getrawmetatable?

I want for string to be able to use the % operator in Lua, but whenever I do this:
getmetatable("").__mod = function(a, b)
if not b then
return a
elseif type(b) == "table" then
return string.format(a, unpack(b))
else
return string.format(a, b)
end
end
errors
attempt to index string with '__mod'
debug.getmetatable doesn't work
debug.getmetatable("").__mod = function(a, b)
if not b then
return a
elseif type(b) == "table" then
return string.format(a, unpack(b))
else
return string.format(a, b)
end
end
errors attempt to call a nil value
So I tried getmetatable("") and it returns "The metatable is locked".
How do I get rid of the "The metatable is locked" thingy in Lua?
I didn't anything to the string metatable. I also found out debug.getmetatable is nil instead of a function.
This thingy also happens to workspace getmetatable(workspace) and the game global getmetatable(game)
I found out synpase got rid of this: https://x.synapse.to/docs/development/objects_mts.html
with a function called getrawmetatable?
How do I add getrawmetatable?
If debug.getmetatable doesn't exist, then you must not be running your script from the standard Lua environment. Instead, you're running it from an application that has embedded Lua into it.
Such an application has total control over what it allows you to access from Lua. So if it has removed debug.getmetatable, and has removed the ability to retrieve the string metatable via getmetatable (by giving the string metatable a __metatable field that is a string), there's nothing you can do from Lua itself to modify said metatable.
Also, unless you have control over the environment (ie: you are the author of the program that is embedding Lua, but if you are, you already know what you did), it's generally bad form to manipulate basic aspects of Lua like the string metatable. Users of Lua in this environment will have no idea what doing % to a string is supposed to mean.
Just type string.format like everyone else.

lua: how to bind my function to the io library

I wrote a lua function write_json which translates lua table into json text.
Is it possible to bind the function with the io library, so that I can use it like this:
mytable = {name="Jack", age="22", score=[12,33,55,66]}
f = io.open("score.json", "wb")
f:write_json(mytable) -- call my function here.
f:close()
You need access to the __index table of the metatable for file objects and put your new methods there:
local metatable = getmetatable( io.stdout )
local indextable = metatable.__index
indextable.write_json = function( file, tab )
-- ...
end
There is another way: The C API function luaL_newmetatable stores the metatable for file objects in the registry under the key "FILE*", so the following will also work (but requires the debug library):
local metatable = debug.getregistry()["FILE*"]
local indextable = metatable.__index
-- ...
There is yet another (more hackish) way: All Lua versions I tested (PUC-Rio Lua 5.1, 5.2, 5.3, and LuaJIT) set the __index field of the metatable to the metatable itself, so you can get at the __index table like that:
local indextable = io.stdout.__index
The best way is probably the first one.
The type of the object returned by io.open is userdata, which I believe cannot be monkey-patched due to its unique nature.

Lua: How to call a function prior to it being defined?

What is the syntax to create the function, but then add it's implementation further down in code?
So roughly like this:
Define function doX
Call doX (further down in the code)
doX implemention (i.e. all functions down at the bottom of the file)
You only need to have a variable to reference. local funcName is sufficient for your purposes with one caveat. This will work:
local funcName
function callIt()
print(funcName())
end
function defineIt()
funcName = function() return "My Function" end
end
defineIt()
callIt()
As long as you define it (defineIt) before you call it (callIt), it should work as expected. You can't do something like this though (and this is the caveat):
local funcName
print(funcName())
funcName = function() return "My Function" end
You will get an error: attempt to call local 'funcName' (a nil value).
oh...so there's really no way to call funcName prior to having actually defined the function then? i.e. you still need to make sure defineIt is called before your first call to funcName itself?
I wanted to clarify this point, and I felt that an answer would be the better way than a comment.
Lua is a much simpler language than C or C++. It is built on some simple foundations, with some syntactic sugar to make parts of it easier to swallow.
There is no such thing as a "function definition" in Lua. Functions are first-class objects. They are values in Lua, just like the number 28 or the string literal "foo" are values. A "function definition" simply sets a value (namely, the function) into a variable. Variables can contain any kind of value, including a function value.
All a "function call" is is taking the value from a variable and attempting to call it. If that value is a function, then the function gets called with the given parameters. If that value is not a function (or a table/userdata with a __call metamethod), then you get a runtime error.
You can no more call a function that hasn't been set in a variable yet than you can do this:
local number = nil
local addition = number + 5
number = 20
And expect addition to have 25 in it. That's not going to happen. And thus, for the same reason, you can't do this:
local func = nil
func(50)
func = function() ... end
As Paul pointed out, you can call a function from within another function you define. But you cannot execute the function that calls it until you've filled in that variable with what it needs to contain.
As others have written, you cannot call a function at runtime that has not been assigned prior to the call. You have to understand that:
function myFunc() print('Something') end
Is just a syntax sugar for this:
myFunc = function() print('Something') end
Now, it makes sense that this kind of code would not work the way you want it to:
print(greeter(io.read())) -- attempt to call global 'greeter' (a nil value)
function greeter(name) return 'Hello '..name end
When you use the greeter variable, its value is nil, because its value is set only on the next line.
But if you want to have your "main" program on the top and the functions at the bottom, there is simple way to achieve this: create a "main" function and call it as the last thing on the bottom. By the time the function is called, all the functions will be set to the corresponding global variables:
-- start of program, your main code at the top of source code
function main()
local name = readName()
local message = greeter(name)
print(message)
end
-- define the functions below main, but main is not called yet,
-- so there will be no errors
function readName() io.write('Your name? '); return io.read() end
function greeter(name) return 'Hello, ' .. name end
-- call main here, all the functions have been assigned,
-- so this will run without any problems
main()

Knowing if a value can be called

Note that this question is about pure Lua. I do not have access to any module or the C side. Additionally, I can not use the IO, the OS or the debug library.
What I'm trying to make is a function that receives, as parameters:
a number that is an ammount of second
a callable value
By 'a callable value', I mean a value that can be called. This can be:
a function
a table with a metatable that allows calling (through a __call metamethod)
Here's an example of a callable table:
local t = {}
setmetatable(t, {
__call = function() print("Hi.") end
})
print(type(t)) --> table
t() --> Hi.
Here's the function:
function delay(seconds, func)
-- The second parameter is called 'func', but it can be anything that is callable.
coroutine.wrap(function()
wait(seconds) -- This function is defined elsewhere. It waits the ammount of time, in seconds, that it is told to.
func() -- Calls the function/table.
end)()
end
But I have a problem. I want the function to throw an error if the parameter 'func' is not callable.
I can check if it is a function. But what if it is a table with a metatable that allows calling?
If the metatable of the table is not protected by a __metatable field, then, I can check the metatable to know if it is callable, but, otherwise, how would I do it?
Note that I have also thought about trying to call the 'func' parameter with pcall, to check if it is callable, but to do that, I need to call it prematurely.
Basically, here's the problem: I need to know if a function/table is callable, but without trying to call it.
In general, if the metatable does not want you to be able to get it (by defining __metatable to being something special), then you're not going to get it. Not from Lua.
However, if you want to cheat, you can always use debug.getmetatable, which will return the metatable associated with that object.
You don't have to prematurely call anything with pcall. Observe:
pcall(function(...) return PossibleFunction(...) end, <insert arguments here>)
function iscallable(x)
if type(x) == 'function' then
return true
elseif type(x) == 'table' then
-- It would be elegant and quick to say
-- `return iscallable(debug.getmetatable(x))`
-- but that is actually not quite correct
-- (at least in my experiments), since it appears
-- that the `__call` metamethod must be a *function* value
-- (and not some table that has been made callable)
local mt = debug.getmetatable(x)
return type(mt) == "table" and type(mt.__call) == "function"
else
return false
end
end
return iscallable
Then you can do
> = iscallable(function() end)
true
> = iscallable({})
false
> = iscallable()
false
> = iscallable(nil)
false
> x = {}
> setmetatable(x, {__call=function() end})
> = iscallable(x)
true
If you don't have access to the debug library, then you may have trouble being totally accurate since you can mess with metatables. You could use pcall but its hard to separate out the errors properly. Even if you search for a particular error string as in the other answer here, that might be because of something inside the function being called not being callable, not this particular value not being callable, if that makes sense.
This attempt at refining Nicol's answer still has the problem that it needs to call the table, but it tells whether a supplied table actually was callable or not. Even if the table was callable, pcall() will return false if there is an error caused during the execution of the __call() metamethod.
local result = {pcall(PossibleFunction, ...)}
if not result[1] then
if result[2]:match"^attempt to call" then
error("The provided value is not callable.")
else
-- Table was callable but failed. Just hand on the error.
error(result[2])
end
end
-- Do something with the results:
for i = 2, #result do
print(result[i])
end
Checking the error message in this way however does not feel very "clean" (what if the used Lua interpreter was e.g. modified with localized error messages?).

Resources