I have a function as follows:
local function mytest(...)
local args={...}
if(#args==1 and type(args[1])=="table") then
local x, mean=nil, nil
for k,v in pairs(args[1]) do
k=string.lower(k)
if(k=="x") then x=v
elseif(k=="mean") mean=v
--the rest is omitted for brevity
end
Then right after the function (in the same script file), I have the following lines:
mytable.test={}
mytable.test.mt={}
mytable.test.mt.__call=mytest
setmetatable(mytable.test, mytable.test.mt)
where mytable is some table in the global space.
When I call the function as follows:
mytable.test{x=Vec, mean=3}
where Vec is of type userdata, it seems that the type of Vec and type of mean are not correctly passed to the local function. As a matter of fact, both seems to be passed as table. However, if I introduce in the following way:
mytable.test=mytest
then everything works as expected. Not sure what point I am missing.
Based on the comment from Luther, the following change solves the problem:
mytable.test={}
mytable.test.mt={}
setmetatable(mytable.test, mytable.test.mt)
function mytable.test.mt:__call(...)
return mytest(...)
end
Related
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() )
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
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.
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()
How do I call a function that needs to be called from above its creation? I read something about forward declarations, but Google isn't being helpful in this case. What is the correct syntax for this?
Lua is a dynamic language and functions are just a kind of value that can be called with the () operator. So you don't really need to forward declare the function so much as make sure that the variable in scope when you call it is the variable you think it is.
This is not an issue at all for global variables containing functions, since the global environment is the default place to look to resolve a variable name. For local functions, however, you need to make sure the local variable is already in scope at the lexical point where you need to call the value it stores, and also make sure that at run time it is really holding a value that can be called.
For example, here is a pair of mutually recursive local functions:
local a,b
a = function() return b() end
b = function() return a() end
Of course, that is also an example of using tail calls to allow infinite recursion that does nothing, but the point here is the declarations. By declaring the variables with local before either has a function stored in it, those names are known to be local variables in lexical scope of the rest of the example. Then the two functions are stored, each referring to the other variable.
You can forward declare a function by declaring its name before declaring the actual function body:
local func1
local func2 = function()
func1()
end
func1 = function()
--do something
end
However forward declarations are only necessary when declaring functions with local scope. That is generally what you want to do, but Lua also supports a syntax more like C, in which case forward declaration is not necessary:
function func2()
func1()
end
function func1()
--do something
end
Testing under the embedded lua in Freeswitch, forward declaration does not work:
fmsg("CRIT", "It worked.")
function fmsg(infotype, msg)
freeswitch.consoleLog(infotype, msg .. "\n")
end
result:
[ERR] mod_lua.cpp:203 /usr/local/freeswitch/scripts/foo.lua:1: attempt to call global 'fmsg' (a nil value)
Reversing the order does (duh) work.
To comprehend how forward referencing in Lua works compared to C, you must understand the a fundamental difference between C compilation and the Lua execution.
In C, forward referencing is a compile time mechanism. Hence if you include a forward declaration template in a C module then any of your code following will employ this template in compiling the call. You may or may not include the function implementation in the same module, in which case both declarations must be semantically identical or the compiler will error. Since this is a compile time construct, the compiled code can be executed in any order.
In Lua, forward referencing is runtime mechanism, in that the compiled function generates a function prototype internally within the code, but this is only accessible as a runtime Lua variable or value after the execution has
passed over the declaration creating a Lua closure. Here the declaration order within the source is immaterial. It is the execution order that is important: if the closure hasn't been bound to the variable yet, then the execution will throw a "nil value" exception.If you are using a local variable to hold the function value, then normal local scoping rules still apply: the local declaration must precede its use in the source and must be within scope, otherwise the compiler will compile in the wrong global or outer local reference. So forward referencing using locals as discussed in other answer will work, but only if the Protos are bound to closures before the first call is executed.
Doesn't work for me if I try to call the function before definition. I am using this Lua script in nginx conf.
lua entry thread aborted: runtime error: lua_redirect.lua:109: attempt to call global 'throwErrorIfAny' (a nil value)
Code snippet -
...
throwErrorIfAny()
...
function throwErrorIfAny()
ngx.say("request not allowed")
ngx.exit(ngx.HTTP_OK)
end
Given some other answers have also pointed out that it didn't work for them either, it is possible that forward declaration of Lua doesn't work with other tools.
PS : It works fine if I put the function definition before and then call it after wards.
If you use OOP you can call any function member prior its "definition".
local myClass = {}
local myClass_mt = { __index = myClass }
local function f1 (self)
print("f1")
self:later() --not yet "delared" local function
end
local function f2 (self)
print("f2")
self:later() --not yet "declared" local function
end
--...
--later in your source declare the "later" function:
local function later (self)
print("later")
end
function myClass.new() -- constructor
local this = {}
this = {
f1 = f1,
f2 = f2,
later = later, --you can access the "later" function through "self"
}
setmetatable(this, myClass_mt)
return this
end
local instance = myClass.new()
instance:f1()
instance:f2()
Program output:
f1
later
f2
later