Attempt to index field (nil value) - lua

Whenever I try to use Body.pos, it always says that it is a nil value. But it is assigned a value in the new function, so it should not be nil.
My code:
Vector={
x=nil,y=nil
,new=function (self,x,y)
o={}
setmetatable(o,self)
self.__index=self
o.x=x or 1
o.y=y or 1
return o
end
-- utility functions here
}
Body={
pos=nil
,vel=nil
,acc=nil
,mass=nil
,new=function (self,pos,vel,acc,mass)
o={}
setmetatable(o,self)
self.__index=self
o.pos=pos or Vector:new()
o.vel=vel or Vector:new()
o.acc=acc or Vector:new()
o.mass=mass or 1
return o
end
,applyForce=function (self,v)
self.acc:add(v:scale(1/self.mass))
end
,applyGravity=function (self)
self.acc:add(GRAVITY_VECTOR)
end
,step=function (self)
self.vel:add(self.acc)
self.pos:add(self.vel)
self.acc:scale(0)
end
}
Trial code:
b=Body:new()
print(b.pos.x) -- shows error that pos is nil
Vector:new() does not return nil, but still Body.pos is always nil. I don't know what I am doing wrong here.
EDIT: Added Vector implementation

The issue is your OOP implementation. The metatable o needs to be set as a local variable.
In your code o is a global variable hence why you always reset it when you create a new object.
Vector={
-- ...
,new=function (self,x,y)
local o={}
-- ...
end
-- ...
}
Body={
-- ...
,new=function (self,pos,vel,acc,mass)
local o={}
-- ...
return o
end
-- ...
}
b=Body:new()
print(b.pos.x) -- 1
Basically any variable that isn't declared as local is automatically put into the global scope.
Additionally I recommend using a linter (e.g. luacheck) to automatically detect issues like this.

Related

I'm getting the error "attempt to index local self (a number value)

require 'class'
Paddle=class{}
function Paddle:init(x,y,width,height)
self.x=x
self.y=y
self.width=width
self.height=height
self.dy=0
end function Paddle:update(dt)
if self.dy < 0 then
self.y = math.max(`enter code here`0, self.y + self.dy * dt)
else
self.y=math.min(VIRTUAL_HEIGHT,-self.height,self.y+self.dy*dt)
end
end
function Paddle:render()
love.graphics.rectangle('fill',self.x,self.y,self.width,self.height)
end
I am following the course CS50 lecture 0 pong update 5, and the same code is working for the teacher. I don't know why this is happening neither understand the problem because it makes no sense. If you want, here's 'class'. This problem isn't happening in the other class I made called 'ball' which does exactly the same thing. I also defined self.dy, and it does have a value "0" so I don't know why it does that error and what that error means.
local function include_helper(to, from, seen)
if from == nil then
return to
elseif type(from) ~= 'table' then
return from
elseif seen[from] then
return seen[from]
end
seen[from] = to
for k,v in pairs(from) do
k = include_helper({}, k, seen) -- keys might also be tables
if to[k] == nil then
to[k] = include_helper({}, v, seen)
end
end
return to
end
-- deeply copies `other' into `class'. keys in `other' that are already
-- defined in `class' are omitted
local function include(class, other)
return include_helper(class, other, {})
end
-- returns a deep copy of `other'
local function clone(other)
return setmetatable(include({}, other), getmetatable(other))
end
local function new(class)
-- mixins
class = class or {} -- class can be nil
local inc = class.__includes or {}
if getmetatable(inc) then inc = {inc} end
for _, other in ipairs(inc) do
if type(other) == "string" then
other = _G[other]
end
include(class, other)
end
-- class implementation
class.__index = class
class.init = class.init or class[1] or function() end
class.include = class.include or include
class.clone = class.clone or clone
-- constructor call
return setmetatable(class, {__call = function(c, ...)
local o = setmetatable({}, c)
o:init(...)
return o
end})
end
-- interface for cross class-system compatibility (see https://github.com/bartbes/Class-Commons).
if class_commons ~= false and not common then
common = {}
function common.class(name, prototype, parent)
return new{__includes = {prototype, parent}}
end
function common.instance(class, ...)
return class(...)
end
end
-- the module
return setmetatable({new = new, include = include, clone = clone},
{__call = function(_,...) return new(...) end})
So this is the part where I call the update function, which is what someone said might be the error
function love.update(dt)
if love.keyboard.isDown('w') then
player1.dy=-PADDLE_SPEED
elseif love.keyboard.isDown('s') then
player1.dy=PADDLE_SPEED
else
player1.dy=0
end
if love.keyboard.isDown('up') then
player2.dy=-PADDLE_SPEED
elseif love.keyboard.isDown('down') then
player2.dy=PADDLE_SPEED
else
player2.dy=0
end
if gameState=='play' then
ball.update(dt)
end
player1.update(dt)
player2.update(dt)
This error is pretty clear on what you're doing wrong.
You're indexing local self, a number value.
That means that somewhere you're doing something like self.dy where self is not a table but a number and using the index operator . on numbers is not allowed as it does not make any sense.
The question is why self is not a table.
function myTable:myFunction() end
is short (syntactic sugar) for
function myTable.myFunction(self) end
and the function call
myTable:myFunction() is short for myTable.myFunction(myTable)
Please refer to the Lua manual.
Function Calls
Function Definitions
Find a function in your code that is defined with : and called with . and gets a number as first argument during that call.
That way a number ends up where you expect self.
I guess the error is in the main.lua which you did not provide.
There you have several calls to Paddle:update(dt). Writing myPaddle.update(dt) would cause that error for example. But I can't tell for sure as you did not provide your code.
But that it works for the teacher, but not for you is usually because you do something different/wrong.
Edit:
As you've provided more code I can tell for sure that the observed error is caused by
ball.update(dt)
player1.update(dt)
player2.update(dt)
This will put dt a number value, where the function expects self, the table ball.
replace it by
ball.update(ball, dt) or ball:update(dt)
player1.update(player1, dt) or player1:update(dt)
player2.update(player2, dt) or player2:update(dt)

Lua table overridden

This is supposed to be a simple backtracking function. The dest is a global table that is being properly edited in the function. The prev table is supposed to keep track of my previous positions as to not revisit them. However, my prev table always turns out empty. I'm a novice. If there is any other helpful information I will be happy to provide it. u
function GoTo(dest, prev)
-- base case
if dest[1] == position[1] and dest[2] == position[2] and dest[3] == position[3] then
return true
end
local prev = prev or {}
-- save destination as to not return here
prev[table.concat(position)] = true
-- create key for next move
local key = {0,0,0}
for i,v in ipairs(dest) do
if dest[i] ~= 0 then
key[i] = dest[i]/math.abs(dest[i])
end
end
-- attempt to move in optimal direction
for i,v in ipairs(key) do
if key[i] ~= 0 then
-- check if next move leads to a visited destination
position[i] = position[i] + v
local check = prev[table.concat(position)]
position[i] = position[i] - v
if not check then
if moveTo(i,v) then
if GoTo(dest, prev) then
return true
end
-- go back
if not moveTo(i, -v) then
error("cannot backtrack")
end
end
end
end
end
end
local prev = prev or {}
You create a local variable in your function and initialize it from a parameter with the same name that is being passed in, which hides all the changes inside the function and that's likely why you don't see any changes for that table. You need to initialize that table outside the function and pass its value in (and remove that local prev statement).

Lua : return table trough function is nil

I get the error: source_file.lua:5: attempt to call a nil value (global 'getCard')
i try to catch the right table in questCards which Index=name is the same as the given string from objName
questCards={{['name']='test1',['creatureName']='test3'},{['name']='test2',['creatureName']='test4'}}
obj='test1'
card=getCard(obj)
card['creatureName']=nil --Only for test purpose
if card['creatureName']==nil then
--do Somthing
end
function getCard(objName)
for k,v in pairs(questCards) do
if v['name']==objName then
return v
end
end
end
The error message is telling you that getCard is not defined at the point where it is called.
You need to define getCard before calling it.

Returning a class in Lua

I'm trying to create a plugin but I can't seem to access the returned player class from outside the GetPlayer() function.
This is the GetPlayer Fuction:
function GetPlayer(Player_To_Find) -- This is the function we use to verify the user exists, It will return the user class if the user exists
LOG("Finding " .. Player_To_Find) --False if they do not exist
local Found = false
local FindPlayer = function(TargetPlayer)
if (TargetPlayer:GetName() == Player_To_Find) then
Found = true
print("Found " .. TargetPlayer:GetName())
return TargetPlayer
end
end
cRoot:Get():FindAndDoWithPlayer(Player_To_Find, FindPlayer)
if Found == true then return TargetPlayer else return false end
end
If I try to call the TargetPlayer class after it has returned using this snippet:
TargetPlayer=GetPlayer(Target)
if TargetPlayer ~= false then
LOG(TargetPlayer:GetName())
It will fail with the error:
attempt to index global 'TargetPlayer' (a nil value)
Can anyone point me in the right direction, It's taken me a long time and I've come up blank.
The parameter TargetPlayer is only in scope in the function body. The TargetPlayer in the last line of GetPlayer refers to a global variable, which is presumably nonexistent and therefore nil.
Declare a local variable in the GetPlayer function, set it in the body of the FindPlayer function, and return it at the end of the of GetPlayer (also don't return false if a player can't be found, return nil, which semantically means "nothing").

How does the __call metamethod in Lua 5.1 actually work?

I'm trying, as an exercise, to make a set implementation in Lua. Specifically I want to take the simplistic set implementation of Pil2 11.5 and grow it up to include the ability to insert values, delete values, etc.
Now the obvious way to do this (and the way that works) is this:
Set = {}
function Set.new(l)
local s = {}
for _, v in ipairs(l) do
s[v] = true
end
return s
end
function Set.insert(s, v)
s[v] = true
end
ts = Set.new {1,2,3,4,5}
Set.insert(ts, 5)
Set.insert(ts, 6)
for k in pairs(ts) do
print(k)
end
As expected I get the numbers 1 through 6 printed out. But those calls to Set.insert(s, value) are really rather ugly. I'd much rather be able to call something like ts:insert(value).
My first attempt at a solution to this looked like this:
Set = {}
function Set.new(l)
local s = {
insert = function(t, v)
t[v] = true
end
}
for _, v in ipairs(l) do
s[v] = true
end
return s
end
ts = Set.new {1,2,3,4,5}
ts:insert(5)
ts:insert(6)
for k in pairs(ts) do
print(k)
end
This works mostly fine until you see what comes out of it:
1
2
3
4
5
6
insert
Very obviously the insert function, which is a member of the set table, is being displayed. Not only is this even uglier than the original Set.insert(s, v) problem, it's also prone to some serious trouble (like what happens if "insert" is a valid key someone is trying to enter?). It's time to hit the books again. What happens if I try this instead?:
Set = {}
function Set.new(l)
local s = {}
setmetatable(s, {__call = Set.call})
for _, v in ipairs(l) do
s[v] = true
end
return s
end
function Set.call(f)
return Set[f]
end
function Set.insert(t, v)
t[v] = true
end
ts = Set.new {1,2,3,4,5}
ts:insert(5)
ts:insert(6)
for k in pairs(ts) do
print(k)
end
Now the way I'm reading this code is:
When I call ts:insert(5), the fact that insert doesn't exist to be called means that the ts metatable is going to be searched for "__call".
The ts metatable's "__call" key returns Set.call.
Now Set.call is called with the name insert which causes it to return the Set.insert function.
Set.insert(ts, 5) is called.
What's really happening is this:
lua: xasm.lua:26: attempt to call method 'insert' (a nil value)
stack traceback:
xasm.lua:26: in main chunk
[C]: ?
And at this point I'm stumped. I have absolutely no idea where to go from here. I hacked around for an hour with varying degrees of increasingly desperate variations on this code but the end result is that I have nothing that works. What undoubtedly obvious thing am I overlooking at this point?
Now the way I'm reading this code is:
When I call ts:insert(5), the fact that insert doesn't exist to be called means that the ts metatable is going to be searched for "__call".
There's your problem. The __call metamethod is consulted when the table itself is called (ie, as a function):
local ts = {}
local mt = {}
function mt.__call(...)
print("Table called!", ...)
end
setmetatable(ts, mt)
ts() --> prints "Table called!"
ts(5) --> prints "Table called!" and 5
ts"String construct-call" --> prints "Table called!" and "String construct-call"
Object-oriented colon-calls in Lua such as this:
ts:insert(5)
are merely syntactic sugar for
ts.insert(ts,5)
which is itself syntactic sugar for
ts["insert"](ts,5)
As such, the action that is being taken on ts is not a call, but an index (the result of ts["insert"] being what is called), which is governed by the __index metamethod.
The __index metamethod can be a table for the simple case where you want indexing to "fall back" to another table (note that it is the value of the __index key in the metatable that gets indexed and not the metatable itself):
local fallback = {example = 5}
local mt = {__index = fallback}
local ts = setmetatable({}, mt)
print(ts.example) --> prints 5
The __index metamethod as a function works similarly to the signature you expected with Set.call, except that it passes the table being indexed before the key:
local ff = {}
local mt = {}
function ff.example(...)
print("Example called!",...)
end
function mt.__index(s,k)
print("Indexing table named:", s.name)
return ff[k]
end
local ts = {name = "Bob"}
setmetatable(ts, mt)
ts.example(5) --> prints "Indexing table named:" and "Bob",
--> then on the next line "Example called!" and 5
For more information on metatables, consult the manual.
You said:
Now the way I'm reading this code is:
When I call ts:insert(5), the fact that insert doesn't
exist to be called means that the ts metatable is going
to be searched for "__call".
The ts metatable's "__call" key returns Set.call.
Now Set.call is called with the name insert which causes
it to return the Set.insert function.
Set.insert(ts, 5) is called.
No, what happens is this:
When insert isn't found directly in the ts object, Lua looks for __index in its metatable.
If it is there and it is a table, Lua will search for insert there.
If it is there and it is a function, it will call it with the original table (ts in this case) and the key being searched for (insert).
If it isn't there, which is the case, it is considered nil.
The error you're having is because you don't have __index set in your metatable, so you are effectively calling a nil value.
This can be solved by pointing __index to some table, namely Set, if you're going to store your methods there.
As for __call, it is used for when you call the object as a function. Ie:
Set = {}
function Set.new(l)
local s = {}
setmetatable(s, {__index=Set, __call=Set.call})
for _, v in ipairs(l) do
s[v] = true
end
return s
end
function Set.call(s, f)
-- Calls a function for every element in the set
for k in pairs(s) do
f(k)
end
end
function Set.insert(t, v)
t[v] = true
end
ts = Set.new {1,2,3,4,5}
ts:insert(5)
ts:insert(6)
ts(print) -- Calls getmetatable(ts).__call(ts, print),
-- which means Set.call(ts, print)
-- The way __call and __index are set,
-- this is equivalent to the line above
ts:call(print)
Set = {}
function Set.new(l)
local s = {}
setmetatable(s, {__index=Set})
for _, v in ipairs(l) do
s[v] = true
end
return s
end
function Set.call(f)
return Set[f]
end
function Set.insert(t, v)
t[v] = true
end
ts = Set.new {1,2,3,4,5}
ts:insert(5)
ts:insert(6)
for k in pairs(ts) do
print(k)
end
I modified your first version and this version would offer the features I think you are looking for.
Set = {}
Set.__index = Set
function Set:new(collection)
local o = {}
for _, v in ipairs(collection) do
o[v] = true
end
setmetatable(o, self)
return o
end
function Set:insert(v)
self[v] = true
end
set = Set:new({1,2,3,4,5})
print(set[1]) --> true
print(set[10]) --> nil
set:insert(10)
print(set[10]) --> true

Resources