Attempt to index global 'self' (a nil value) _ - lua

I ran this code and it gave me an error attempt to index global 'self' (a nil value)
hook.Add("Think", "Cooking", function()
local Position = self:GetPos() + self:GetAngles():Up()*20
local rawFood = ents.FindByName("my_raw_food")
for k, v in pairs(rawFood) do
if(Position:Distance(v:GetPos()) <= 25) then
v:Remove()
timer.Create(self:EntIndex() .. "my_food", 5, 1, function() self:createFood() end)
end
end
end )

It's hard to say without seeing more of the code, especially the scope around your code.
But it sounds like "self" doesn't exist in the scope. Either it should be supplied as a parameter to the function:
hook.Add("Think", "Cooking", function(self)
print(self) -- uses the 'self' parameter
end)
or it should be available in the scope of declaring the function, and it'll be part of the closure:
function MyClass.addHook(self) -- same as MyClass:addHook()
hook.Add("Think", "Cooking", function()
print(self) -- uses the 'self' in scope (la MyClass instace)
end)
Though, self can of course be nil even if it's declared in the scope. Calling MyClassInstance.addHook() instead of MyClassInstance:addHook() is the most common.

self is used when using object oriented programming as described in the documentation 16 - Object-Oriented Programming.
In order to use self you must implicitly pass it as the first argument or not.
I mean...
myObject = { id = 1 }
function myObject:hello( name )
print( "hello " .. name .. " I'm object id : " .. tostring( self.id ) )
end
// Using the . char the object must be the first argument
myObject.hello( myObject, "world" )
// Using the : char the obect is automatically set as the first arg
myObject:hello( "world" )
So in your code, I guess you should use the : char.
hook:add(...)

Related

lua - differece of : and . when define function?

hope you having great day , i'm test some stuff with lua, and i got some error
i have this codes in Object.lua
local Object = {name = "Object"}
Object.__index = Object
function Object.new()
local t = setmetatable({}, Object)
return t
end
function Object:keys(table)
local keyset={}
local n=0
for k,v in pairs(table) do
n=n+1
keyset[n]=k
end
return keyset
end
return Object
and i call Object.keys in "Other" script like this
local Object = require("lua.app.common.utils.Object")
local t = {
[1] = a,
[2] = b,
[3]= c
}
Object.keys(t)
and this cause error with
Exception has occurred: bad argument #1 to 'for iterator' (table expected, got nil),
because the parameter 'table' is passed as nil ( i don't know why thuogh debug mode just says its a nil)
on the other hand, if i fix object.keys(table) to object:keys(table), everything works fine, why this error happening?
Declaring the method keys with a colon adds an implicit self parameter as the first argument which requires you to call the method in the same way, using the colon.
Calling the method with the period notation expects you to supply the self parameter but because you only pass in t this is interpreted as self and then nil is added for your table parameter.
Declaring the method with a colon you actually have this
function Object:keys(self, table)
but calling it with the period means you have done this
Object.keys(t, nil)
hence the "table expected, got nil" error

Dynamic reference to Lua table method, param passed in is null

I'm creating a dynamic table method reference and trying pass a single param to the method. The dynamic method reference does work and the table method is called just as expected, however the completely not nil param I'm passing to the method is nil inside the method. Can you point out my error in these 2 lines?...
Here is a small working example that demonstrates. On first line in the Consider:Move method, mons is nil
local Consider = {}
function Consider:Move( mons )
print( 'Mons ' .. mons.type .. ' considering Move...')
actionChosen.score = 0
return actionChosen
end
local mons = { type = 'Blue' }
local actionPref = 'Move'
local considerAction = Consider[actionPref]
print( 'MonsterAI:chooseAction mons: ', mons.type )
local actionTest = considerAction( mons )
Functions defined using the colon operator hides an additional first self argument. function Consider:Move(mons) is syntactic sugar for function Consider.Move(self, mons).
Calling the function like considerAction(mons) sets the hidden self argument instead of the desired one.
You might want to pass the Consider table as self:
considerAction(Consider, mons)
Or, alternatively, define the function using the dot operator if you don't need self:
function Consider.Move(mons)
print('Mons ' .. mons.type .. ' considering Move...')
end

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.

quoting troubles in Lua

I am trying to make a quote function in lua, so i can use the arguments as strings but without quotes or access them in some environment. Much like in the second comment on this question
w = print
function test()
local function _ix( _ , k )
w( " _ix \\ " , _ , k )
local v = rawget( _G , k )
w( " <-- " , k )
return k
end
local _ = setmetatable( {} , { __index = _ix } )
local function q( _ ) return _ end
q = setfenv( q , _ )
return q
end
So, when I run it:
q = test()
w( "q( uno )" , q( uno ) )
It doesn't even call the __index metamethod:
---------- Capture Output ----------
q( uno ) nil
> Terminated with exit code 0.
So, what I'm doing wrong?
If I'm understanding correctly, then what you're trying to do doesn't make much sense. uno will be looked up in the environment that q is called in, not with. In your example it's like calling q(nil). The example from the other question works because they're working in the same, global environment.
You can use write a helper function to intercept your current environments nil-lookups, but it must be called preemptively in any environment you want to use these nil-to-string lookups.
local function intercept (tab)
setfenv(2, setmetatable(tab or {}, {
__index = function (_, key)
return key
end
}))
end
And you'll need an environment cloning function, unless you want to manually create your sandboxes every time, else you'll probably mess up parent environments (e.g., _G). You could move this logic inside of intercept for a cleaner function call, but with less flexibility.
local function clone_current_env ()
local env = {}
for key, value in pairs(getfenv(2)) do
env[key] = value
end
return env
end
Using them together, you can cause nil lookups in whichever environment you're in to become strings.
intercept(clone_current_env())
print(type(foo), type(bar)) --> string string
This is some ugly metaprogramming, and I don't really know why you'd want to write code like this, except as a proof of concept.
A full example.
DEMO
local function clone (tab)
local new = {}
for key, value in pairs(tab) do
new[key] = value
end
return new
end
local function enable_nil_strings ()
setfenv(2, setmetatable(clone(getfenv(2)), {
__index = function (env, key)
return key
end
}))
end
local function disable_nil_strings()
setmetatable(getfenv(2), nil)
end
-----------------------------------------------------
print(type(foo), type(bar)) --> nil nil
enable_nil_strings()
print(type(foo), type(bar)) --> string string
disable_nil_strings()
print(type(foo), type(bar)) --> nil nil
Finally, arguably the best way to implement this would be to simply wrap around an execution context:
local function with_nil_strings (context, ...)
local env = {}
for key, value in pairs(getfenv(2)) do
env[key] = value
end
setfenv(
context,
setmetatable(env, {
__index = function (_, key) return key end
})
)
context(...)
end
print(type(foo)) --> nil
with_nil_strings(function ()
print(type(foo)) --> string
end)
print(type(foo)) --> nil

Metatables, attempt to call method 'rename' (a nil value)

This is my first time using metatables, I did a simple script to test in Lua demo but it always give me "attempt to call method 'rename' (a nil value)", why?
peds = {}
function peds.new ( name )
local tb = { name = name }
setmetatable ( tb, { __index = peds } )
return tb
end
function peds.rename ( name )
self.name = name
return self.name == name
end
local ped = peds.new ( "max" )
ped:rename ( "randomname" )
There's two (possible) problems in your code, depending on how you are setting things up.
If you are just typing the above into a REPL, then when you declare local ped = ... it immediately goes out of scope and becomes inaccessible. So the expression ped:rename is invalid, although it should report "ped is nil" not "rename is nil".
If you are saving the above to a script and loading it using load_file or something, you will still get a problem, because this function signature isn't right:
function peds.rename ( name )
should be:
function peds.rename ( self, name )
Similar to how it works in C++, in lua, when you make an object method, you have to take the hidden self parameter first, and when you call ped:rename( "random name" ) that's just syntactic sugar for ped.rename(ped, "random_name"). If the self parameter doesn't exist then it's not going to work, or may even say "function not found / rename is nil" because the signatures don't match up.

Resources