Weird "attempt call field "drawers"(a table value)" error - lua

I was working on this project about a year ago. I came back to it and now it throws an error when I run it the error is "attempt call field "drawers"(a table value)".
This is where the drawers field is
local Renderer = {}
local num_of_layers = 2
local insert = table.insert
local remove = table.remove
function Renderer:create()
local render = {}
render.drawers = {}
for i = 0, num_of_layers do
render.drawers[i] = {}
end
function render:addRenderer(obj, layer)
local l = layer or 0
insert(self.drawers(l), i, obj)
end
return render
end
return Renderer
This is where it is being called
local tlm = {}
function tlm:load()
renderer:addRenderer(self)
gameloop:addLoop(self)
end

This is not correct:
insert(self.drawers(l), obj)
self.drawers is not a function but a table. therefor a function call like self.drawers(1) results in an error.
If you wanted to insert an element to the table self.drawers at index l using Luas standard functions you should call:
table.insert(self.drawers, i, obj)
If you want to replace the value at index l you can simply write self.drawers[l] = obj
http://www.lua.org/manual/5.3/manual.html#pdf-table.insert

Related

ComputerCraft (Lua) Can "attempt to index a nil value"error be trapped to prevent the script from haulting

I've written a Lua script for ComputerCraft to control a mob farm. What I'm doing is checking the amount in specific Functional Storage drawers. The API for the mod has, at least to me, a weird quark that if the storage drawer is empty then the call to getItemDetail(num).count fails and returns "Attempt to index a nil value."
I was able to determine that if you just call getItemDetail(num), where num is the index of the drawer, and the drawer is empty then it returns nil. This works some of the time. It fails if that between calling getItemDetail(num) and getItemDetail(num).count the drawer's count goes from >0 to 0 it errors with "Attempt to index a nil value." At least this is my current working theory as to why it fails.
Is there any better way of trapping the index a nill value error so that the program doesn't error and hault?
This is how I'm currently trying to determine if the drawer has a 0 count or not.
data is table of class objects where I keep track of things like the location, index, of the drawers.
-- If you call getItemDetail and it returns nil, then the drawer is empty.
-- If you call getItemDetaiil(num).count it throws a error "Attempt to index a nill value."
if storage.getItemDetail(data[i]:getLocation()) ~= nil then
storageamount = storage.getItemDetail(data[i]:getLocation()).count
else
storageamount = 1
end
if storage.getItemLimit(data[i]:getLocation()) ~= nil then
storagelimit = storage.getItemLimit(data[i]:getLocation())
else
storagelimit = 1024
end
The code loops until the drawer is full and then moves on to the next item.
The class definition for clairity.
Class = {
-- Constructor
new = function(self)
local new = {}
setmetatable(new, {__index = self})
return new
end,
-- Setters
setName = function(self, name) --Tag of item in drawer
self.name = name
end,
setLocation = function(self, location) -- Drawer location from Controller
self.location = location
end,
setRSI = function(self, RSI) -- This is the side of the Computer of the RSI
self.RSI = RSI
end,
setSide = function(self, Side) -- This is the side of RSI that will out RS signal
self.Side = Side
end,
--Getters
getName = function(self, name)
return self.name
end,
getLocation = function(self,location)
return self.location
end,
getRSI = function(self, RSI)
return self.RSI
end,
getSide = function(self, Side)
return self.Side
end
}
The code runs just fine as long as one of the drawers that I'm monitoring doesn't go to zero.
So I really want to be able to trap the error or prevent the program from haulting if encounters the index a nill value error.
Thanks,
You could just store the value of storage.getItemDetail(data[i]:getLocation()) in a variable, check if that variable is not Nil, and get the item's count, something like this:
item = storage.getItemDetail(data[i]:getLocation())
storagelimit = storage.getItemLimit(data[i]:getLocation())
storageamount = 1
if item ~= nil then
storageamount = item.count
end
if storagelimit == nil then
storagelimit = 1024
end

Get Reference to Calling Function in Lua

I know I can use debug.getinfo(1, "n").name to get the calling function's name, but I would like to get a reference to that function pointer itself.
For debug.getlocal(), the f parameter is the stack position so I can easily get the locals for the calling function by just choosing the correct index. But for debug.getupvalue(), the f parameter is the function pointer itself, which I don't have.
Here is a brief example, but with the offending line debug.getupvalue(someFunction, index) there to demonstrate what I would like to accomplish, without the hard-coded reference.
local someUpValue = "stackoverflow"
function someFunction()
local value1 = "hi"
local value2 = "there"
local value3 = someUpValue
log()
end
function log()
local callingFuncName = debug.getinfo(2, "n").name
local index = 1
while(true) do
local name, value = debug.getlocal(2, index)
if name then
print(string.format("Local of %s: Name: %s Value: %s", callingFuncName, name, value))
else
break
end
index = index + 1
end
index = 1
while(true) do
local name, value = debug.getupvalue(someFunction, index)
if name then
print(string.format("Upvalue of %s: Name: %s Value: %s", callingFuncName, name, value))
else
break
end
index = index + 1
end
end
someFunction()
You can use debug.getinfo(2, "f").func to get the function reference (assuming you are calling from the function you want to get a reference to):
function log()
local callingFuncRef = debug.getinfo(2, "f").func
callingFuncRef(false) -- this will call the function, so make sure there is no loop

table.insert doesn't trigger __index?

I made a custom table using metatables that automatically tracks sizing when elements are added. It works very well and removes the need for the # operator or the getn function.
However it has a problem. If you call table.insert, the function apparently never calls __index or __newindex. Thus, my table cannot know when elements are removed this way. I assume the problem is the same with table.remove as well.
How can I either:
Capture the event of insert and use my own function to do so
Throw an error if insert is called on my table.
Thanks
function Table_new()
local public = { }
local tbl = { }
local size = 0
function public.size()
return size
end
return setmetatable(public, {
__newindex = function(t, k, v)
local previous_v = tbl[k]
rawset(tbl, k, v)
if previous_v ~= nil then
if v == nil then
size = size - 1
end
elseif v ~= nil then
size = size + 1
end
end,
__index = tbl
})
end
local t = Table_new()
t[5] = "hi"
t[17] = "hello"
t[2] = "yo"
t[17] = nil
print(t.size()) -- prints 2
local z = Table_new()
table.insert(z, "hey")
table.insert(z, "hello")
table.insert(z, "yo")
print(z.size()) -- prints 1 -- why?
If you print k,v in __newindex, you'll see that k is always 1. This is because table.insert asks for the size of table to find where to insert the value. By default, it's at the end. You should add a __len metamethod. But perhaps this defeats your purposes (which are obscure to me).

why passing an argument to lua class method get nill

I have a method that builds a Tree from a parent list pointer in lua.
In particular I have this lua table
parents = {2,3,13,5,12,7,11,9,10,11,12,13,14,0}
Along with two functions:
Function 1 (creates the node):
function create_node(parent, i, created, root)
if created[i] ~= nil then
return
end
print(i)
-- print(parent)
-- Create a new node and set created[i]
local new_node = Tree()
new_node.idx = i
created[i] = new_node
-- If 'i' is root, change root pointer and return
if parent[i] == 0 then
root[1] = created[i] -- root[1] denotes root of the tree
return
end
-- If parent is not created, then create parent first
if created[parent[i]] == nil then
create_node(parent, parent[i], created, root )
end
print(i)
-- Find parent pointer
local p = created[parent[i]]
print (p)
if #p.children <=2 then
print(p.idx)
print(created[i].idx)
p.add_child(created[i])
end
end
Function 2 (creates the tree recursively):
I have stopped the loop at one to test the first path from leaf to root i.e 1-2-3-13-14
function read_postorder_parent_tree(parents)
n = #parents
-- Create and array created[] to keep track
-- of created nodes, initialize all entries as None
created = {}
root = {}
for i=1, 1 do
create_node(parents, i, created, root)
end
return root[1]
end
The create_note method uses the below Tree class:
local Tree = torch.class('Tree')
function Tree:__init()
self.parent = nil
self.num_children = 0
self.children = {}
end
function Tree:add_child(c)
print(c)
c.parent = self
self.num_children = self.num_children + 1
self.children[self.num_children] = c
end
Everything works fine but when I call p.add_child(created[i]) the argument is nil why? (why c is nil?) I have already checked that created[i] and p are not nil. How can i solve this and/or why this happening?
This is the error that I get:
./Tree.lua:16: attempt to index local 'c' (a nil value)
stack traceback:
./Tree.lua:16: in function 'add_child'
main.lua:120: in function 'create_node'
main.lua:109: in function 'create_node'
main.lua:109: in function 'create_node'
main.lua:109: in function 'create_node'
main.lua:134: in function 'read_postorder_parent_tree'
main.lua:153: in function 'main'
main.lua:160: in main chunk
[C]: in function 'dofile'
...3rto/torch/install/lib/luarocks/rocks/trepl/scm-1/bin/th:150: in main chunk
[C]: at 0x00405d50
If you define a function in an object-oriented way, you must also call it in the same way.
function Tree:add_child(c)
This declares a function in an object-oriented way using the colon operator. To help you understand what that means, it can be rewritten like this:
Tree.add_child = function(self, c)
As you can see, an implicit self parameter is created to reflect the object the function was called on. However, you call the function via the standard way:
p.add_child(created[i])
Now you can see that what you really did was pass created[i] as self, not as c, which then of course happens to be nil. The standard way to call such a function is also via the colon operator:
p:add_child(created[i])
This implicitly passes p as self to the actual function, and now p will contain the actual argument.

attempt to call method 'func' (a nil value)

No matter how I approach Lua, I run into this error all the time, so I must not understand something inherit to the language:
attempt to call method 'func' (a nil value)
I've seen the error here a few times as well but the problem doesn't seem clear to me.
Here's my module:
actor.lua
Actor = {
x = 0,
mt = {},
new = function()
local new_actor = {}
new_actor.x = Actor.x
new_actor.mt = Actor.mt
return new_actor
end,
test = function(self, a, b)
print(a, b)
end
}
I'm using Löve.
main.lua
require "game/actor"
local a = Actor:new() --works fine
function love.load()
a.x = 10
print(a.x) --output: 10
a:test(11, 12) --error: attempt to call method 'test' (a nil value)
end
I'm also not sure when it's appropriate to use the previous styling over this in a module.
Actor = {
x = 0
}
Actor.mt = {}
function Actor.new()
print(42)
end
I'm honestly not sure what is more correct than the other but considering I run into a simple error either way, there's probably something I'm missing entirely?
It looks like you're trying to instance a kind of class made of metatables. You basically need to assign new_actor's metatable with Actor.mt. (Resuming the problem: when you're indexing new_actor you're not indexing Actor in this case)
setmetatable(new_actor, Actor.mt);
Even if the metatable is being added, it won't work until you put the meta "__index" event to index a table containing your class methods/values, in this case:
Actor.mt = {
__index = Actor
};
I'd suggest moving your class methods/values into a new table, like Actor.prototype, Actor.fn, etc... avoiding conflicts:
Actor.fn = {
test = function(self, a, b)
print(a, b)
end
};
Actor.mt = {
__index = Actor.fn
};
More about metatables in Lua 5.3 manual.

Resources