I'd like to create MyClass class in Lua in a separate file myclass.lua which I can import and use later.
It should be working the following way:
local MyClass = require 'myclass'
tab = {1,2,3}
m = MyClass(tab)
However, following the code in Lua docs I can't make it work and am getting errors attempt to call global 'MyClass' (a table value).
The code I have written so far for myclass.lua:
local MyClass = {}
MyClass.__index = MyClass
function MyClass.__init(tab)
self.tab = tab or {}
setmetatable({},MyClass)
return self
end
return MyClass
There is a plethora of examples how to write classes in Lua but I don't think I understand the difference and as a result getting lost in the implementation details. Is there a more or less conventional way to do it?
In Lua, you cannot usually call a table like you would call a function. For example, this code will produce an error of "attempt to call local 't' (a table value)".
local t = {}
t()
There is a way of making this work by using metatables, however.
local hello = {}
local mt = {} -- The metatable
mt.__call = function ()
print("Hello!")
end
setmetatable(hello, mt)
hello() -- prints "Hello!"
When you try and call a table as you would a function, Lua first checks to see whether the table has a metatable. If it does, then it tries to call the function in the __call property of that metatable. The first argument to the __call function is the table itself, and subsequent arguments are the arguments that were passed when the table was called as a function. If the table doesn't have a metatable, or the metatable doesn't have a __call function, then an "attempt to call local 't'" error is raised.
Your example code has three problems:
You are trying to use __init instead of __call. Lua doesn't have an __init metamethod.
__call takes different parameters than the ones you are using. The first parameter to the __call function is the table itself. You can either use function MyClass.__call(self, tab), or use the colon syntax, function MyClass:__call(tab), which implicitly adds the self parameter for you. These two syntaxes are functionally identical.
You haven't set a metatable for the MyClass table. While you are setting a metatable for MyClass's objects, that doesn't mean that a metatable is automatically set for MyClass itself.
To fix this, you could do something like the following:
local MyClass = {}
setmetatable(MyClass, MyClass)
MyClass.__index = MyClass
function MyClass:__call(tab)
local obj = {}
obj.tab = tab or {}
setmetatable(obj, MyClass)
return obj
end
return MyClass
This sets MyClass to use itself as a metatable, which is perfectly valid Lua.
The system of metatables is very flexible, and allows you to have just about any class/object scheme you want. For example, if you want, you can do everything inline.
local MyClass = {}
setmetatable(MyClass, {
__call = function (class, tab)
local obj = {}
obj.tab = tab or {}
setmetatable(obj, {
__index = MyClass
})
return obj
end
})
return MyClass
As well as being concise, this also has the advantage that people can't change the class's metamethods if they have access to the class table.
There is no __init metamethod available for a table. When you do the following:
m = MyClass(tab)
it looks for the MyClass.__call method definition. Just update your myclass.lua as:
local MyClass = {}
MyClass.__index = MyClass
function MyClass:__call(tab)
self.tab = tab or {}
setmetatable({},MyClass)
return self
end
return MyClass
Related
I have the following scenario in which the position of code shall not change. How to modify this code to fix the error without moving the function and table variable. I am a Lua newbie, just 4 days
function a()
print("function a");
end
ftable = {
["a"] = a,
["b"] = b
};
function b()
print("function b");
end
ftable["a"](); -- prints 'function a'
ftable["b"](); -- attempt to call field 'b' (a nil value)
Update : Using the following mechanism its possible to do this.
function a()
print("function a");
end
ftable = {
["a"] = a,
["b"] = "b"
};
function b()
print("function b");
end
ftable["a"](); -- prints 'function a'
_G[ftable["b"]]();
Lua's table declaration and function definition (and function calling syntax) is very flexible. You can use the field key as an identifier instead of the index syntax, provided that the key is a string and is also a valid identifier ({ a = a } and ftable.a()). This seems to be the case with your a and b keys. You can also make the field assignment with the function definition statement (function ftable.b…).
function a()
print("function a")
end
ftable = {
a = a
}
function ftable.b()
print("function b")
end
ftable.a() -- prints 'function a'
ftable.b() -- prints 'function b'
Of course, you could also move "function a" down and code it like "function b". that would leave ftable = { } at the top.
One difference from your code. The global variable b is no longer set to the function. In most cases, this would be considered an advantage.
I would also like to re-iterate what #lhf said,
There are no declarations in Lua, only definitions.
A function definition (in the general case) is an expression. When evaluated, it produces a function value. Various types of statements can assign the value to a variable or field, as does function ftable.b()….
You can't do that. There are no declarations in Lua, only definitions. You need to define variables before using them.
What you can do is to register the names of the functions in ftable and then fix the values before using them:
ftable = {
["a"] = true,
["b"] = true,
}
...
for k,v in pairs(ftable) do ftable[k]=_G[k] end
This code assumes that your functions are defined globally.
I have this Lua code to initialize a table:
table = {
a = 1;
b = myfunc();
c = function () <some code> end;
}
After this table.c has type function and I have to use table.c()
in a print statement with the .. operator to get the result. But I would like to just use table.c instead.
Is there a way that I can get the return value of the function assigned to table.c so the type is not function without having to define a function outside of the table?
If you wanted table.c to contain the return value of the function, then you should have assigned it the return value of the function. You instead assigned it the function itself.
To get the return value of a function, you must call that function. It's really no different from b. myfunc is a function; myfunc() is calling that function and storing its return value.
But, due to Lua's grammar, calling a function that you are defining requires that you need to wrap the function constructing expression in (), then call it:
c = (function () <some code> end)();
This of course will only contain the value of that function at the time that the table is constructed.
How to define functions into lua's table? I try this code but doesn't work.
I want to use table:myfunc().
local myfunc
myfunc = function(t)
local sum = 0
for _, n in ipairs(t) do
sum = sum + n
end
return sum
end
mytable = {
1,2,3,4,5,6,7,8,9
}
print(myfunc(mytable)) -- 45
I think myfunc has not problem.
table.myfunc = myfunc
print(mytable:myfunc())
-- lua: main.lua:18: attempt to call method 'myfunc' (a nil value)
-- stack traceback:
-- main.lua:18: in main chunk
-- [C]: ?
print(mytable) shows table: 0x9874b0, but it is not defined function to the table?
mytable.myfunc = myfunc
print(mytable:myfunc()) -- 45
This worked. Is it the only prefer way to do this?
there are plenty of ways to define a function within a table.
I think the problem with your first code is that you have this:
table.myfunc = myfunc
where it should be:
mytable.myfunc = myfunc
In your case mytable.myfunc is nil as you never assigned a value to it
You could just write
local mytable = {}
function mytable.myfunction()end
or
mytable.myfunction = function()end
or
mytable["myfunction"] = function()end
or define myfunc separately and assign it to mytable.myfunc later like you did
If you want to access other table members from your function I recommend defining the function like that:
function mytable:myfunc()end
which is syntactic sugar for
function mytable.myfunc(self)end
If you do so you can access mytable's member trough the keyword self
In your case it would end up like:
function mytable:myfunc()
local sum = 0
for _, n in ipairs(self) do
sum = sum + n
end
return sum
end
So you don't need the function parameter t anymore and you can run the desired mytable:myfunc()
Otherwise you would have to write mytable:myfunc(mytable).
table.myfunc = myfunc
print(mytable:myfunc())
This cannot work, because mytable has no member called myfunc, table does.
you would either have to write
table.myfunc = myfunc -- assign myfunc to TABLE (not the same as mytable)
print(table.myfunc(mytable)) -- as with most other functions in table
or
mytable.myfunc = myfunc -- assign myfunc to MYTABLE
print(mytable:myfunc()) -- syntactic sugar for print(mytable.myfunc(mytable))
also, you can just define the function as either
function mytable:myfunc() -- syntactic sugar for mytable.myfunc(self)
-- do something
-- use "self" to access the actual table
end
or
function table.myfunc(t)
-- do something
end
so i have a lua file analogous to this:
x = { __index = x}
constructor = function()
local o = {}
return setmetatable(o,x)
end
function x:print()
print("hello world")
end
i type the following into the interpretr:
dofile "file.lua"
a = constructor()
a:print() --error attempt to call method 'print' (a nil value)
dofile "file.lua"
a = constructor()
a:print() -- hello world
the method works the second time i import the file but not the first. why is this?
I have tried changing the order (putting the constructor function last) and it was the same.
The first time x is nil. It gets defined and then used the second time.
You need to write x = {}; x.__index = x.
I know this question seems simple, but I want to know the difference between two ways of creating functions in Lua:
local myFunction = function()
--code code code
end
Or doing this
local function myFunction()
--code code code
end
The difference happens if the function is recursive. In the first case, the "function" name is not yet in scope inside the function body so any recursive calls actually refer to whatever the version of "myFunction" that was in scope before you defined your local variable (most of the times this meas an empty global variable).
fac = "oldvalue"
local fac = function()
print(fac) --prints a string
end
To be able to write recursive functions with the assignment pattern, one thing you can do is predeclare the variable:
local myFunction
myFunction = function()
-- ...
end
Predeclaring variables also happens to be the only way to define a pair of mutually recursive local functions:
local even, odd
even = function(n) if n == 0 then return true else return odd(n-1) end end
odd = function(n) if n == 0 then return false else return even(n-1) end end
The difference is that according to the manual:
The statement
local function f () body end
translates to
local f; f = function () body end
not to
local f = function () body end
(This only makes a difference when the body of the function contains references to f.)
The main reason is that the scope of a variable (where the variable is visible) starts AFTER the local statement, and if a function was recursive, it would not reference itself, but a previous local or a global named f.