How to store a table method in a different table? - lua

I would like to store methods that are associated with a table, so that I can randomly select one of the function using math.random. Storing functions in a table and calling those functions is straight forward, as shown below:
function funcA()
print("A")
end
functionTable = {funcA}
functionTable[1]()
However, I cannot store a function from a table (a method?) in a new table. The following code will return in an Error (Lua 5.4): function arguments expected near '}'
local functionStore = {}
function functionStore:funcA()
print("A")
end
functionStore:funcA()
functionTable = {functionsStore:funcA}
functionTable[1]()
I think the colon (:) means that I'm already calling the function?, and then the error would make sense, but I would like to store the function in the table.
What Am I doing wrong here?

The problem is that the colon is a special syntactic sugar for function calls to pass the variable / expression preceding it as first argument to the function; it can not be used as an expression. You can however write yourself a function that "curries" the self argument, creating a closure:
local function curry_self(self, methodname)
return function(...) return self[methodname](self, ...) end
end
then you can use this as follows:
functionStore:funcA()
functionTable = {curry_self(functionsStore, "funcA")}
functionTable[1]()
Alternatively, you may pass self as you invoke the function:
functionStore:funcA()
functionTable = {functionStore.funcA}
functionTable[1](functionStore) -- pass functionStore as `self`
In your case, you don't need the colon at all though - you don't even use self in your function! Thus, you may use:
local functionStore = {}
function functionStore.funcA()
print("A")
end
functionStore.funcA()
functionTable = {functionsStore.funcA}
functionTable[1]()
you can put functions in a table without using the colon, using just the dot to assign them to table fields.

Related

Lua attempt to index global 'self' error (GMod Lua script)

I have been getting the following error with this section of code:
[ERROR] lua/entities/cook/init.lua:58: attempt to index global 'self' (a nil value)1. cooked - lua/entities/cook/init.lua:58
The function starts at line 57, and when I remove line 58 (local Pos = self.Entity:GetPos() , it just gives the same error message for line 61.
function cooked()
local Pos = self.Entity:GetPos()
local roll = math.random(1, 5);
if roll == 5 then
self.Entity:EmitSound("phx/explode06.wav")
self.Entity:Remove()
else
local createfood = ents.Create("food")
createfood:SetPos(Pos + Vector(0,10,100))
createfood:Spawn()
self:SendLua("GAMEMODE:AddNotify(\"You finish cooking the food and package the product!\", NOTIFY_GENERIC, 4)")
end
end
It's unclear what self should be. The error says it's a global, which is consistent with the code you have shown.
But, self is almost exclusively used as a formal parameter to a function and an implicit one at that.
When self is implicit, the function is called a method because the intent is for it to access fields in a table passed into self. The method value is almost always held by a field in the same table (or at least, available as such via metamethods).
The colon syntax in a function definition creates a method.
If cooked was a method then it would make sense for it to access self. But cooked is a global.
You might have meant:
function sometable:cooked()
-- ...
-- self is an implicit formal parameter
-- ...
end
How to read the Lua statement above:
access sometable as a table
assign its "cooked" field the function value created by the function definition.
(The function definition is compiled from the method syntax, so in the body, self is the first formal parameter, which is implicit.)
The method could be called like:
sometable:cooked() -- passes sometable as self
The colon syntax in a field function call is a method call.
How to read the Lua statement above:
access sometable as a table,
index its "cooked" field,
call its value as a function, passing sometable as the first parameter,
discard the result list.
Oddities:
The syntax for methods is just "syntactic sugar." Methods values are no different than other function values:
A function created from a function definition using the any syntax can be called using any function call syntax.
A method need not be called using the method call syntax.
A non-method can be called using the method call syntax.
self is not reserved so it can be used as any identifier is.
Self is nil, so how do you call cooked()?
It has to be self.cooked(self) or self:cooked(), where self is the table you want to use as self in your function.

Function reference retrieved from table won't accept any arguments

I have a table of function references as follows:
KLC.ChatCommandBank = {
test = KLC.TestFunction,
config = KLC.OpenInterfaceOptions,
option = KLC.OpenInterfaceOptions,
options = KLC.OpenInterfaceOptions,
help = KLC.PrintHelp
};
but when f = "test" and t is a table of strings and I call
KLC.ChatCommandBank[f](t);
then the function
function KLC:TestFunction(tab)
print(tab);
end
has a nil value for tab, despite the fact that when the function is called, t is not nil.
I suspect this is due to the table of function references not having arguments defined; I haven't been able to find anything with a google and my own tinkering couldn't fix it! Any input appreciated
It's because when you define function as KLC:TestFunction(tab) it gets one implicit parameter self that refers to the table it's called on.
When you call it as KLC.ChatCommandBank[f](t), you need to explicitly pass something in place of that parameter:
KLC.ChatCommandBank[f](KLC, t)
Alternatively, you can change the definition to local function KLC.TestFunction(tab).

Attempt to index local 'self' (a nil value)

I have a problem with classes. I got below error:
Attempt to index local 'self' (a nil value)
When I call the getter method of below class.
Item.lua file:
require "classlib"
Item = class("Item")
function Item:__init()
self.interval = 1
end
function Item:getInterval()
return self.interval
end
I'm calling this getter function like this:
dofile("../src/item.lua")
item = Item()
function test_item()
assert_equal(1, item.getInterval())
end
What's the problem here?
Kind regards...
In general, you should call member functions by :.
In Lua, colon (:) represents a call of a function, supplying self as the first parameter.
Thus
A:foo()
Is roughly equal to
A.foo(A)
If you don't specify A as in A.foo(), the body of the function will try to reference self parameter, which hasn't been filled neither explicitly nor implicitly.
Note that if you call it from inside of the member function, self will be already available:
-- inside foo()
-- these two are analogous
self:bar()
self.bar(self)
All of this information you'll find in any good Lua book/tutorial.
the obj:method is just syntactictal sugar for:
definition:
function obj:method(alpha) is equivalent to obj.method(self,alpha)
execution:
obj:method("somevalue") is equivalent to obj.method(obj,"somevalue") Regards
Change:
assert_equal(1, item.getInterval())
to:
assert_equal(1, item:getInterval())
In Lua, it was some ridiculous for error reporting. From class point of view, the .getInterval() method should called with a self parameter, while the :getInterval() method is implicitly included the self parameter. And the syntax error should labeled in the called point, not the definition-body of getInterval().
In traditional, while you miscalled a method, it was not the method's fault, but the caller.

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()

In Lua, how can I know if a table contains a class function?

Say I declare a lua function using the : operator like so:
function ClassName:myFunc( stuff )
--do stuff
end
And then say I store that function in a table like so:
someTable = {
ClassName.myFunc,
someGlobalFunc,
}
And then, say I have another function that goes through the table and attempts to call the given functions.
function ClassName:callStuffInThisTable(table)
-- I go through the table, which might be someTable above, and call all the functions
end
My question is, how do I know if a function in the table is owned by ClassName, so that I can call it using self?
You don't. At least, Lua isn't going to tell you.
function ClassName:myFunc( stuff ) is just syntactic sugar as far as Lua is concerned. It's no different from this: ClassName.myFunc = function (self, stuff). The functions are equivalent.
Likewise for the : call syntax, ClassName:myFunc(stuff) is semantically equivalent to ClassName.myFunc(ClassName, stuff).
It is up to you to know what your functions are and what they do. This requires coding discipline. If you have a list of functions that you need to call in a loop, then they should be designed to be called with the same parameters.
There are two ways to do this. One way is to make all of the functions "class functions":
someTable = {
ClassName.myFunc,
function(self, ...) return someGlobalFunc(...) end,
}
This way, the self parameter is ignored. Obviously, you could create a special function table object that has functions for inserting "global" functions into the table that will automatically generate the wrapper:
function insertFuncIntoTable(self, func)
self[#self + 1] = function(self, ...) func(...) end
end
insertFuncIntoTable(someTable, someGlobalFunc)
Note: there is a difference between these, assuming "someGlobalFunc" is actually a member of the global table (rather than a local). This version will take the value that _G["someGlobalFunc"] currently has, just as your original code does. However, the first version takes the value that it has at the time it is called, which may be a different function from the one it was at the time someTable was created.
So this version is safer.
Alternatively, you can make it so that any "class functions" in the table are explicitly bound to an object instance:
someTable = {
function(self, ...) ClassName.myFunc() end,
function(self, ...) return someGlobalFunc(...) end,
}
BTW, in general, if you declare a function using : syntax, you're supposed to use that function that way, via instance:myFunc(...). Obviously it's just a Lua function like any other, so you can do what you like. But misuse can make understanding what's going on harder.
Lua affords you a lot of power. But you're still required to exercise judgement and discipline when coding. Lua will not save you from yourself (entirely).
One way to tell if the function is "owned" by ClassName would be to scan and check.
ClassName = {}
function ClassName:fn(self) ... end
t = { function() ... end , ClassName.fn() }
function has_value( klass, value )
for k,v in pairs(klass) do
if v==value then return true
end
return false
function ClassName:callStuffInThisTable(table)
for k,v in pairs(table) do
if has_value(ClassName, v) then
v(self)
else
v()
end
end
end
This has O(n^2) behaviour though due to the table scan. We can reduce this to O(n log(n)) ) by using the functions in ClassName as a new table
function ClassName:callStuffInThisTable(table)
local t = {}
for k,v in pairs(ClassName) do
t[v] = 1
end
for k,v in pairs(table) do
if t[v]==1 then
v(self)
else
v()
end
end
end

Resources