Reputation: 13
I'm trying to tidy up some code a bit and to create a function generator. So I'm passing a bunch of arguments to a function creating a nested function; first of them is the desired name of the nested function.
function gen (name)
return
{
function name ()
return
{
...
}
end
}
end
Then I call gen
function a couple times with different names to get multiple name
functions with different values inside.
And obviously it doesn't work as I want it to. The exact error I'm getting is
'(' expected near 'name'
Surprisingly when I use a name = function ()
notation I get some other error far downstream.
I've played with the code a little, but my knowledge is not enough to use any construct but the initial extremely bulky version.
Update #1 This
function gen (self, name, arg2)
return
{
[name] = function (arg3)
return
{
data = arg3
}
end
}
end
for k,v in pairs (gen (name, "xarg")) do print(k,v) end
print (xarg)
returns
xarg function: 0x1365390
nil
And with _G[name]
I have no luck at all.
Update #2
So I haven't found a solution and switched to use of t[name]
at the cost of discarding the (arg3)
.
Upvotes: 1
Views: 1255
Reputation: 741
There are some basic misunderstandings here, so I'll try to break it down step by step. Consider the first part of the initial given code.
function gen (name) -- define a function named "gen"
return -- return
{ -- a table
function name () -- containing a function...
-- et cetra ...
When you write a pair of matched curly braces {...}
in Lua you are defining a table. Things you write inside the braces become the contents of the table. This is called a table constructor.
The error you are getting in this code is because you have tried to write a statement where Lua expects an expression. The difference between these things is somewhat technical, but basically, expressions represent a value and may contain things like numbers, strings, operators, table constructors and function calls. A statement is a piece of code that represents an action like assigning an expression to a variable, a function call (which can be an expression or a statement), or a complex structure like an if
or while
block (which probably has other statements inside).
function name() ... end
is a statement in Lua because it assigns the function to the global variable name
. It is also possible to have an function as an expression, but then you can't give it a name (in the same way). This looks like function() ... end
. That's why Lua said it was expecting (
after function
. Giving an expression a name in Lua in the same thing as an assignment, so it is a statement.
This may be a little bit confusing in the case of a table constructor, as you can put something that looks a lot like an assignment statement inside of a table constructor. For example {x = 3}
or {name = function() ... end}
are perfectly fine expressions, but here the x =
or name =
means something different than it does as a statement outside of a table constructor. It doesn't mean to assign to a variable called x
or name
, but instead to add a field to the table with that name.
For example:
table1 = {x = 3}
print(x) -- nil
print(table1.x) -- 3
table2 = {name = function() print("hello!") end}
name() -- error!
table2.name() -- hello!
Now, consider
function gen(name)
function name()
print("hello!")
end
end
When you put an identifier between function
and ()
, Lua uses literally what you wrote as the name of the function. So:
gen("f")
f() -- error
name() -- hello!
You need to do something special to assign a value to a variable that is determined at run-time. For local variables, this is possible only with the debug API (and only then for variable names that already exist otherwise). For global variables, you can use the global table.
When you assign a value to a global variable, Lua internally has to keep track of it somehow. It does this using a table, just the same as any other table. By default, the variable _G
contains a reference to that table.
print(x) -- nil
print(_G.x) -- nil
x = 3
print(x) -- 3
print(_G.x) -- 3
_G.x = 4
print(x) -- 4
print(_G.x) -- 4
print(_G == _G._G) -- true
If used as I did above, this isn't very useful. However, remember that in Lua, table.x
is actually shorthand for table["x"]
. By using the []
syntax instead of the .
syntax, we gain the flexibility to do define a global variable dynamically.
_G["y"] = 5
print(y) -- 5
print(_G.y) -- 5
print(_G["y"]) -- 5
print(z) -- nil
name = "z"
_G[name] = 6
print(z) -- 6
This is essentially what lhf's answer does. It defines assigns a function to a global variable with a name determined by the argument of the surrounding function. It should work perfectly if you want to define a global function.
Now consider your second answer block of code:
function gen (self, name, arg2)
return
{
[name] = function (arg3)
-- et cetra ...
Here again, we are in a table constructor, so we are not defining a global variable, we are creating a table field whose value is a function. As before, using the []
syntax allows the field's name to be determined by the name
variable. Consider:
table = gen(nil, "xarg")
-- table = {xarg = function(arg3) return {data = arg3} end}
print(table.xarg) -- function ...
table2 = table.xarg("mydata")
print(table2.data) -- mydata
table3 = table.xarg("myotherdata")
print(table3.data) -- myotherdata
print(table2 == table3) -- false
-- you can assign this to a global variable if you want later
-- (but then why put it in a table to begin with?)
xarg = table.xarg
print(xarg("mythirddata").data) -- mythirddata
name2 = "xarg2"
table_xarg2 = gen(nil, name2)
_G[name2] = table_xarg2[name2]
print(xarg2("mylastdata").data) -- mylastdata
This also works fine if your intent is to for the function to be stored in the table.
You have to decide where you want your function to be stored, and put it there. In either the global environment or as a field in a table, you can choose the name based on the argument of a function.
Note that the function itself doesn't have a name. Lua functions don't inherently have names. They are just (usually) stored in variables or fields, and the name of the variable or field is thought of as the name of the function.
Another possibility, then, is to not give a name inside the generator at all. For example:
function gen(arg1)
return function(arg2)
return {data1 = arg1, data2 = arg2}
end
end
xarg1 = gen("a1")
xarg2 = gen("a2")
record1 = xarg1("b1")
record2 = xarg2("b2")
print(record1.data1) -- a1
print(record1.data2) -- b1
print(record2.data1) -- a2
print(record2.data2) -- b2
Upvotes: 2
Reputation: 72312
If you want to create a global function named name
, then use
function gen (name)
_G[name] = function ()
-- body here
end
end
Upvotes: 1