Lua attempt to call method a nil value - lua

I'm lost on what I'm doing wrong here.
I have this simple code:
Queue = {}
Queue.__Index = Queue
function Queue.Create()
local obj = {}
setmetatable(obj, Queue)
return obj
end
function Queue:PushBack(item)
end
q = Queue.Create()
print(q)
q:PushBack(1)
When executing this I get "attempt to call method 'PushBack' (a nil value). However, if I change the PushBack function like this and call it accordingly it works:
function Queue.PushBack(q, item)
end
q = Queue.Create()
print(q)
Queue.PushBack(q, 1)
The code runs and executes correctly. I understand that ":" is syntactic sugar, so it seems to me that
function Queue:PushBack(item)
would be exactly the same as
Queue.PushBack(q, item)
But it dies on me. Does it have to do with how I'm creating the object? I'm pretty lost on this and I can't seem to figure out what exactly is wrong.

The nil signifies that the PushBack function is not found in the first case.
The reason your code doesn't work, is because you have unintentionally misspelt __Index as it should be:
Queue.__index = Queue
with i of __index being lower-case.
Once corrected, your code should work.

Related

Is there an easy way to unpack two arrays/varargs in Lua?

Lets take a look at this pseudo code example:
-- Wraps a function with given parameters inside a callback
-- Usefull for sending class methods as callbacks.
-- E.g. callback(object.method, object)
local function callback(func, ...)
return function(...)
func(..., ...)
end
end
How would I go about this?
I know there is unpack, but it would get swallowed by the second vararg:
local function callback(func, ...)
local args = { ... }
return function(...)
func(table.unpack(args), ...)
end
end
callback(print, "First", "Second")("Third") --> prints First Third
The only option I found so far, is to concat those together and then unpack it:
local function callback(func, ...)
local args1 = { ... }
return function(...)
local args2 = { ... }
local args = { }
for _, value in ipairs(args1) do
table.insert(args, value)
end
for _, value in ipairs(args2) do
table.insert(args, value)
end
func(table.unpack(args))
end
end
Is this the only solution, or could I do better?
What I would like to have is either a function, that concats two arrays together (which should be faster than those two for loops) and then use table.unpack on it, or make those varargs concat.
From the Lua 5.4 Reference Manual: 3.4 Expressions
If an expression is used as the last (or the only) element of a list
of expressions, then no adjustment is made (unless the expression is
enclosed in parentheses). In all other contexts, Lua adjusts the
result list to one element, either discarding all values except the
first one or adding a single nil if there are no values.
So the only way is to manually combine both lists to a single one befor you use them.
There are several ways to do this.
for i,v in ipairs(list2) do
table.insert(list1, v)
end
for i,v in ipairs(list2) do
list1[#list1+i] = v
end
table.move(list2, 1, #list2, #list1 + 1, list1)
I'm not sure what kind of problem you're actually trying to solve here.
If you want to access your object from its methods use self.
-- Wraps a function with given parameters inside a callback
-- Usefull for sending class methods as callbacks.
-- E.g. callback(object.method, object)
Usually you would do something like this:
local callback = function(params) object:method(params) end
callback(params)
Instead of
callback(print, "First", "Second")("Third")
You could do this
local callback = function (...) print("First", "Second", ...) end
callback("Third")
Edit ( opinonated )
My main goal is to use member functions as callbacks. However, I'd
like to keep it general. The advantage of a callback function is to
omit the function and end keyword. It's shorter and looks closer to
what it would look like, if there would be no need for a self
argument. So this: object.event = function(...) return
self:method(...) end would become to this: object.event =
callback(self.method, self) what would be even nicer, is this (sadly
not possible in lua) object.event = self:method
So instead of
RegisterCallback(function() obj:method() end)
You say it is easier to do this, so you don't have to write function end?
local function callback(func, ...)
local args1 = { ... }
return function(...)
local args2 = { ... }
local args = { }
for _, value in ipairs(args1) do
table.insert(args, value)
end
for _, value in ipairs(args2) do
table.insert(args, value)
end
func(table.unpack(args))
end
end
RegisterCallback(callback(obj.method, obj)())
Your approach is not going to work if any of the arguments is nil to begin with. And there is not a single advantage. You're just typing other words while increasing the chance of running into errors.
You can control the param order to optimize your function.
local function callback(func, ...)
local args = {...}
return function(...)
func(..., table.unpack(args))
end
end
callback(print, "second", "third")("first") -- prints first second third

Getting "attempt to index a nil value error" when attempting to create objects in Lua

I'm putting some code into a module so I can draw and maintain multiple copies. I'm getting this common error but I can't see why. I understand what it's saying to a basic level, but as I'm able to see a print out from the table being created, I don't understand why calling a function that module contains would throw this error.
I've read through all the answers on SO, but I'm still at a loss. I've tried printing out at various stages to see where the issue is, everything works as if I had created an instance of the module, but the error persists.
Code below is cleaned of extraneous stuff.
local orbitalCircle = include('lib/orbital_circle')
function init()
c1 = orbitalCircle.new(20, 42, 18, 1.7, 16, 62, 15, c1Sequence)
<-- at this point print code from the module's init function works
c1:doFunc(param) <-- this will call the error
The module:
local Orbital_Circle = {}
-- set up variables
local some Vars Are here
function Orbital_Circle.new(x, y, diameter, scale_factor, number_of_notes, beats_per_second, frames_per_second, sequence_data)
print("Orbital_Circle running")
end
function Orbital_Circle:doFunc(param)
self.var = param <-- I update a local var here
print("self.var") <-- I then print the updated number for sanity checking
end
return Orbital_Circle
I expect the var in my instance of this module to update and the functions code to run, but... no joy. I get the error.
Cheers.
I'm putting some code into a module so I can draw and maintain multiple copies.
I think there's a bit of a misunderstanding about how Lua modules work here. It's an easy mistake to make.
When you require a module in Lua, each subsequent require of the same file refers to the same code. So (eg) these two variables contain exactly the same code:
local orbitalCircle1 = require('lib/orbital_circle')
local orbitalCircle2 = require('lib/orbital_circle')
Which means that you can't use Lua modules by themselves to create OOP type objects as you are trying to do. Your new function must return something that can be used like an instance of a class, a unique table for each call:
local Orbital_Circle = {}
local shared_variable = 1
function Orbital_Circle.new(x, y)
-- create unique table
local obj = {}
-- access these from table/object methods with self.xxx
obj.x = x or 0
obj.y = y or 0
obj.var = "initial value"
-- now define functions with an explicit 'self' parameter...
function obj.doFunc(self, param)
self.var = self.var .. " " .. param
shared_variable = shared_variable + 1
end
-- ... or with the syntactic 'self' sugar, ':'
function obj:printVars()
print("self.var = " .. self.var)
print("shared_variable = " .. shared_variable)
print("self.x = " .. self.x)
end
return obj
end
return Orbital_Circle
You can also define the methods as local functions outside the new function that have self parameter and have a list of entries such as:
obj.anotherMethod = functionDeclaredAtTopOfFile
… to keep things tidier, if you like.
Your code is completely messed up.
<-- will cause an error for unexpected symbol.
c1 = orbitalCircle.new(20, 42, 18, 1.7, 16, 62, 15, c1Sequence)
will give you an error for indexing a global nil value c1 because orbitalCircle.new has no return value.
your init function is incomplete and you don't call it so the provided code does not do anything even if you fix the above errors.
The reported error is not caused by any line of code you provided here.
Code below is cleaned of extraneous stuff.
I'm afraid you removed too much.
The error message tells you that you're indexing local n, a nil value from within a local function that has been defined in n's scope.
This code for example:
local n
function test()
local b = n.a
end
test()
would result in the error message:
input:3: attempt to index a nil value (upvalue 'n')
n is an upvalue for test because it is a local variable defined outside the functions body, but not a global variable.

Post-hook a function, post-process and pass through all returns

I have a post-hook function that receives some data for itself, reference to another function and arguments for that arbitrary function in .... This function does some post-processing, after referenced function returns. For simplicity let's just note time:
function passthrough(tag, func, ...)
metric1[tag] = os.time()
func(...)
metric2[tag] = os.time()
end
Since I need to postprocess, I can't immediately return func(...) and I don't know in advance how many returns there will be. How can I passthrough those returns after I'm done with post-processing?
So far I can think only of packing call in local results = { func(...) } and then using return unpack(results) or making a postprocessor factory that'd generate postprocessing closure with all necessary data as upvalues:
local function generate_postprocessor(tag)
return function(...)
metric2[tag] = os.time()
return ...
end
end
function passthrough2(tag, func, ...)
metric1[tag] = os.time()
return generate_postprocessor(tag)(func(...))
end
However, both those approaches would introduce some overhead that is undesirable, considering high amount of iterations and real-time nature of application. Is there anything simpler?
You don't need the closure. func is called before calling your closure generator anyway. You just need a function that passes its arguments straight through to its return values to give you a hook point for your second tag:
function passthrough_return(tag, ...)
metric2[tag] = os.time()
return ...
end
function passthrough(tag, func, ...)
metric1[tag] = os.time()
return passthrough_return(tag, func(...))
end
You're still getting the overhead of an extra function call, but that's better than creating a closure or a table and far less than the overhead of your pre/post processing.

why can't this Lua function using a self ":" be marked "local" without getting "'(' expected near ':'"

Why can't this Lua function using a self ":" be marked "local" without getting:
'(' expected near ':'
That is, in the code below things work. But why can't I make the "scene:createScene" function local (as I get the above-mentioned error when trying).
I note the listener functions need to be made local else I have struck cross-scene issues at times in storyboard. These can be marked local and work fine.
SceneBase = {}
function SceneBase:new()
local scene = Storyboard.newScene()
local function returnButtonTouch_Listener (event)
-- code here
end
function scene:createScene( event ) -- WHY CAN'T THIS BE LOCAL???
-- code here
end
return scene
end
return SceneBase
That is why can't the function line read:
local function scene:createScene( event )
function scene:createScene(event) ... end
Is syntax sugar for:
scene.createScene = function(self, event) ... end
Which is syntax sugar for:
scene["createScene"] = function(self, event) ... end
You want to do:
local scene["createScene"] = function(self, event) ... end
Which makes no sense.
Another way of putting it: local is a qualifier for a variable which makes it local rather than global. What variable would you be qualifying with local function scene:createScene( event )?
createScene is not a variable, it's a key in the table scene.
Actually, that's a bit misleading. When you say:
foo = 10
Without qualification, foo becomes global, which is to say it's stored in the global state like this:
_G.foo = 10;
Which of course means the same as this:
_G["foo"] = 10;
When you use the keyword local, it doesn't get stored in a table, it ends up stored in a VM register, which is both faster and has more tightly constrained scope.
When you write either of these:
function foo.bar() end
function foo:bar() end
You are explicitly storing the function value in a table (foo). Those statements are exactly equivalent to these, respectively:
foo["bar"] = function() end
foo["bar"] = function(self) end
I note the listener functions need to be made local
What do you mean by that? In Lua, a function is a function is a function. It's just another value, like a string or number. Whether it's stored in a global, table, local, or not stored at all is irrelevant.
local foo = print
_G["zap"] = foo
doh = zap
t = { zip = doh }
t.zip("Hello, World") -- Hello, World
assert(print == foo
and zap == foo
and zap == doh
and t.zip == doh)
Here we pass the print function around. It's all the same function, and as long as we have a reference to it we can call it.
I don't know Corona, but I'm guessing that event handlers are not specified by naming convention of locals. You need to register it as an event handler. For instance, according to this video a Button object has an onEvent field which is set to the handler for that button.

Error while trying to call a class method: attempt to index local 'self' (a nil value) - Lua

I'm creating a lua script that should run on the TI-Nspire calculator. The problem is that while running my script I get the error Attempt to index local 'self' (a nil value) when the button:activate() method is called. The parser says the error is in the 8th line in the code below. The problematic code is as follows:
button = class(view)
function button:init()
self.selected = false
end
function button:activate()
self.selected = true
end
I call the activate function like this:
item = button()
local action = "activate"
local arguments = {}
item[action](unpack(arguments))
I am aware the class() function doesn't exist in "stock" Lua, it's a function available in the TI-Nspire Lua implementation. You can find its definition and usage here.
obj:methodname(args) is sugar for obj.methodname(obj,args). So, if you want to use the syntax item[action](unpack(arguments)), you need to use item[action](item,unpack(arguments)). Otherwise, try item:activate(unpack(arguments)) if you can use method explicitly.

Resources