How to get 'self' from Lua event handler function? - lua

local tbl = {a = 1}
-- Passed and executed function
function tbl:handleFunc(x, y)
print(self.a + x + y)
end
-- I know the above code is syntax sugar.
-- tbl["handleFunc"] = function(self, x, y)
-- print(self.a + x + y)
-- end
-- Register event handlers that I can't control the call
Frame:SetScript("OnClick", tbl.handleFunc)
-- Probably called when an event occurs.
tbl.handleFunc(2, 3)
-- Then it will be like this.
tbl.handleFunc(2, 3, nil)
-- So I wrote a function like this
function tbl.handleFunc(x, y)
local self = tbl -- This variable is too cumbersome
-- And this way, every time I call a function, I need to check whether the function definition is a dot (.) Or colon (:)
end
When calling a function, In situations where you can't pass self, Is there a way to use self?
If not, how should I design?
[Solved] I used a translator but I want to be polite. Thank you for the nice answers.

One way to avoid unnecessary work is to write a function that will wrap the function for you before you register it as a handler:
local tbl = {a = 1}
function tbl:handleFunc(x, y)
print(self.a + x + y)
end
function wrap_with(obj, func)
return function(...)
return func(obj, ...)
end
end
Frame:SetScript("OnClick", wrap_with(tbl, tbl.handleFunc))

Just use an anonymous function that calls the actual function
Frame:SetScript("OnClick", function(x,y) tbl:handleFunc(x, y) end)

Related

Wrap an iterator to iterate over only some of the values

I have a Lua iterator function that I don't have control over:
for x, y, z in otherfunc(stuff) do
...
end
I want to write a generic Lua wrapper to this function that skips over some of the values it returns, hiding this implementation detail from my users:
for x, y, z in myfunc(stuff) do
-- not every x/y/z triplet will appear here
end
Though I happen to have three return values here, how can I handle this generically for any number of return values?
local function check_and_return(my_state, x, ...)
if x == nil or my_state[1](x, ...) then
return x, ...
else
return check_and_return(my_state, my_state[2](my_state[3], x))
end
end
local function my_generator(my_state, prev_x)
return check_and_return(my_state, my_state[2](my_state[3], prev_x))
end
function subiterate(selector, generator, state, init_x)
-- the iterator is stateless
-- no closures created at loop initialization
-- one table is created at loop initialization
-- no tables created on every step
return my_generator, {selector, generator, state}, init_x
end
Usage example:
local function everythird(i,_)
return (i-1)%3==2
end
for i, n in subiterate(everythird, ipairs{'a','b','c','d','e','f'}) do
print(i, n)
end
--> 3 c
--> 6 f
For the specific case of a known iterator function with specific number of return values, and a hard-coded selection criteria, I used this:
function myfunc(...)
local generator, constant, x,y,z in otherfunc(...)
return function()
repeat x,y,z = generator(constant,x,y,z)
until (not x) or x+y+z > 7
if x then return x,y,z end
end
end
The above will call the otherfunc() iterator repeatedly, but only yield x/y/z values when the sum of them is greater than 7.
More generically, here's a function that takes a selection function and an iterator, handling an arbitrary number of return values from the iterator and returning them only when the selector function returns a truthy value:
function subiterate(selector, generator, constant, ...)
local values = {...}
return function()
repeat values = table.pack(generator(constant, table.unpack(values)))
until not values[1] or selector(table.unpack(values))
return table.unpack(values)
end
end
local function everythird(i,_)
return (i-1)%3==2
end
for i, n in subiterate(everythird, ipairs{'a','b','c','d','e','f'}) do
print(i, n)
end
--> 3 c
--> 6 f
I make no guarantees about the speed of the generic function, given all the pack() and unpack() going on. But it does work. I welcome any more efficient way to handle arbitrary numbers of return values for an iterator.

Lua: colon and dot function invocation acting differently

I initially came across this while developing my game in LOVE2D, and I can't figure out why.
As much as I know, x:foo() is just a syntactic sugar for x.foo(self) but combining this with other classes results in some weird behavior.
Basically, I have two programs
y = {}
function y:bar()
return self.b
end
x = {}
function x:foo()
return y.bar(self)
end
print(x.foo({b = 3}))
This prints 3 as expected
y = {}
function y:bar()
return self.b
end
x = {}
function x:foo()
return y:bar()
end
print(x.foo({b = 3}))
But this prints nil !!
I don't understand, why are these two programs printing different things?
x:foo() is syntactic sugar for x.foo(x)
which means that
function x:foo()
return y:bar()
end
is actually
function x:foo()
return y.bar(y)
end
look again at your use of self
function x:foo()
return y.bar(self) -- = y.bar(x)
end
function x:foo()
return y:bar() -- = y.bar(y)
end
x:foo() is just a syntactic sugar for x.foo(self)
This is correct in the context of a function definition but not as an expression.
function x.y.z:foo(a, b)
print(self, a, b)
end
is the same as
function x.y.z.foo(self, a, b)
print(self, a, b)
end
A function definition being set into a table field can be a method, that is with a :. Nested table fields are also allowed, for methods and non-methods, if the keys are strings that are valid Lua identifiers, as in x.y.z.
But
print(x.y().z:foo(a, b))
is the same as
local _ = x.y().z
print(_.foo(_, a, b))
With the method call syntax, the lefthand-side of : is an expression (x.y().z) that is evaluated only once.

Is there any reason not to unpack simple values in Lua

Let's say I do unpack(4) or unpack("hello world"). Are there any unexpected behaviors to this?
Reason is something like this:
function a(bool)
if bool then
return {1, 2}, "foo"
else
return 1, "foo"
end
end
function b(x, z)
end
function b(x, y, z)
end
i, j = a(???)
b(unpack(i), j) -- is this ok?
unpack(4) will cause an error
attempt to get length of a number value
unpack("hello world") will return
nil nil nil nil nil nil nil nil nil nil nil
so that's not very useful as well.
unpack is meant for unpacking tables. If you'd work with a recent version of Lua you would notice that it is now table.unpack()
Other issues with your code:
Lua does not support overloading functions. Functions are variables.
You write:
function b(x, z)
end
function b(x, y, z)
end
The first definition is lost once the second definition is processed.
If you use the another notation it will be more clear.
Your code is equivalent to
b = function (x, z)
end
b = function (x, y, z)
end
and I think you will agree that after
b = 3
b = 4
b will be 4. Same principle...
You can amend the unpack standard function to obtain the desired behavior:
local old_unpack = table.unpack or unpack
local function new_unpack(list, ...)
if type(list) ~= "table" then
list = {list}
end
return old_unpack(list, ...)
end
table.unpack = new_unpack
unpack = new_unpack
-- Usage:
print(unpack(4))
print(unpack("hello world"))
print(unpack(nil)) -- ops! nothing is printed!

Is it possible to define functions globally in Lua's table

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

What is the difference between local function myFunction and local myFunction = function()

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.

Resources