Override Lua instance function - lua

I'm trying to change the behavior of a Lua function, by adding code to the start or end of it. Because this is a mod for a game, I can't edit the function directly, so I have to override it instead. I accomplish this by storing a reference to the original function in a local variable, then redefining the function with my own, which calls the original one along with any prefix or postfix code I need to add, like so:
local base_exampleFunction = ExampleBaseGameClass.exampleFunction
function ExampleBaseGameClass.exampleFunction(param1, param2)
--Prefix code goes here
base_exampleFunction(param1, param2);
--Postfix code goes here
end
This works fine for functions defined with the ClassName.functionName syntax, but some functions use ClassName:functionName instead, which from what I understand, are functions that pass a reference to the class instance as the first parameter. I can't figure out how to prefix/postfix these functions, as I get the following error when declaring a variable to hold the original function if I try the same approach:
attempted index: exampleFunction of non-table: null
Is there a way to make this work?

: functions are just scary ways of saying "the first argument is self".
So, ExampleBaseGameClass:exampleFunction(param2) is equivelent to ExampleBaseGameClass:exampleFunction(ExampleBaseGameClass, param2)! It's just got self at the beginning, and functions declared with : will have an invisible self variable appear out of nowhere.
local a = {}
function a.b(self)
print(self)
end
function a:c()
print(self)
end
-- a.c(a) == a:c()
-- a:b() == a.b(a)
-- a:b() == a:c()
Using this idea, we can simply prepend an argument (it does not have to be called "self", it just has to be the first argument).
This should work, unless there is a part of your Lua environment (eg, funky metatables) which would prevent such a thing:
local base_exampleFunction = ExampleBaseGameClass.exampleFunction
function ExampleBaseGameClass.exampleFunction(self, param1, param2)
--Prefix code goes here
base_exampleFunction(self, param1, param2);
--Postfix code goes here
end
The lua library takes advantage of the first argument being the calling object for it's string library. Notice how ("hello"):gsub() works--by passing the string itself as the first argument!

Related

What is happening when you have a function as a parameter?

I'm still ramping up in lua, and I am not quite familiar with this syntax. What is happening when you pass in a function as a parameter like below?
Comm.setRouting(function(url)
for i = 1,4 do
local portIndex = "Path"..i
if url:match(portConfig[portIndex]) ~= nil then
return Comm.slots()[1], Comm.groups()[i]
end
end
end)
The other answers are correct, but it might help you if you wrote your own function that calls another function:
function CallAFunction(func_to_call)
func_to_call()
end
You could pass a named function (an anonymous function assigned to a variable) or an anonymous function written on the fly.
function SayHello()
print("Hello!")
end
--[[
^This is equivalent to:
SayHello = function()
print("Hello!")
end
]]--
CallAFunction(SayHello)
CallAFunction(function()
print("Goodbye!")
end)
output:
Hello!
Goodbye!
and this can be done with parameters
function CallAFunction(func)
func("Bonjour")
end
CallAFunction(function(parameter)
print(parameter)
end)
Here, func is the anonymous function, which accepts 1 parameter parameter.
When you call func("Bonjour") you are passing Bonjour as parameter, like a normal function call.
Here you're passing an argument to setRouting that is an "anonymous function"
Functions are first-class values in Lua and can be stored in local variables, global variables and table fields. Here the function is being passed anonymously on the call stack to the setRouting function.
setRouting would be called a "higher-order function" because it accepts a function as its input.
The following page has some more information about functions in Lua:
https://www.lua.org/pil/6.html
A couple of things are happening in this example:
You're passing a function as a parameter. The callee (e.g. setRouting()) can invoke that function. This is often referred to as a callback function.
You're defining the function itself, on-the-fly. This is an example of an "anonymous function", or a lambda function.

Why does io\open not work in moonscript?

Moonscript uses \ to call methods so can someone explain to me why the code below does not work:
> file = io\open("mix.exs", "rb")
[string "tmp"]:1: calling 'open' on bad self (string expected, got table)
but when you call it to read the file it does ?
> file\read!
"Code.ensure_loaded?(Hex) and Hex.start
The io.open function expects to get a string as the first argument but io\open (like io:open in lua itself) is actually passing the io table as the first argument. That is it is a method call.
io\open("file", "mode")/io:open("file", "mode") are syntactic sugar for io.open(io, "file", "mode").
This is why file\read! works without an explicit argument because file gets passed as the first argument to the read("file", "format") function.
Moonscript uses \ to call methods
to call member methods. as in a\b c, ... translates to a.b(a,c,...).
this doesn't work here because io.open is a static function (io.open(what,how)), not a member (io.open(self,what,how)).
you couldn't call io:open in Lua either. the only place where io functions allow for being called as members is when you want to read/write stdio.
but when you call it to read the file it does ?
because now it's a member method of the file. you're actually still using io.read there, but the file object has io as a metatable index, therefore allowing you to access the same function via file.read, and since file\read! translates to file.read(file) it's the same thing.
so essentially the answer boils down to "because io:open doesn't work in Lua".

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.

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

Forward define a function in Lua?

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

Resources