Reputation: 6429
I'm probably missing something very simple, but when calling a method on an object in Lua, is there a way to get the name of that object from the self
variable?
To illustrate what I mean, here is a somewhat contrived example - a simple Stack implementation:
Stack = {}
function Stack:new (...)
instance = {}
instance.elements = {...}
setmetatable(instance, self)
self.__index = self
return instance
end
function Stack:push (...)
for i,v in pairs({...}) do
table.insert(self.elements,v)
end
end
function Stack:pop ()
if #self.elements > 0 then
return table.remove(self.elements)
else
error("Cannot pop, Stack is empty")
end
end
my_stack = Stack:new(2,4)
my_stack:push("dog") -- my_stack.elements = {2,4,"dog"}
print(my_stack:pop()) -- "dog"
print(my_stack:pop()) -- "4"
print(my_stack:pop()) -- "2"
print(my_stack:pop()) -- error: "Cannot pop, Stack is empty"
Is it possible to use the self
variable in the Stack:pop
error message to output the name of the object it's being called from? I'd like the error message to say "Cannot pop, Stack 'my_stack' is empty
".
Upvotes: 3
Views: 3959
Reputation: 23757
local function get_my_self_name(self)
local i = debug.getinfo(3, 'Sl');
return "'"..(io.open(i.source:match'@(.*)'):read'*a'
:gsub('.-\n','',i.currentline-1)
:match('(.-)[:.]%s*'..debug.getinfo(2,'n').name..'%s*%(')
:match'([%w_]+)%s*$' or '<unnamed>').."' at line #"..i.currentline
end
local Stack = {}
function Stack:new (...)
local instance = {}
instance.elements = {...}
setmetatable(instance, self)
self.__index = self
return instance
end
function Stack:push (...)
for i,v in ipairs({...}) do
table.insert(self.elements,v)
end
end
function Stack:pop ()
if #self.elements > 0 then
return table.remove(self.elements)
else
error("Can't pop, Stack "..get_my_self_name(self).." is empty")
end
end
local my_stack = Stack:new(2,4)
my_stack:push("dog") --my_stack.elements = {2,4,"dog"}
print(my_stack:pop()) --"dog"
print(my_stack:pop()) --"4"
print(my_stack:pop()) --"2"
print(my_stack:pop()) --error: Can't pop, Stack 'my_stack' at line #35 is empty
Upvotes: 4
Reputation: 29571
is there a way to get the name of that object from the self variable?
Objects in Lua don't have names. Only references have names, and variables and table fields are ultimately just references to objects. So if you are asking how to get the name of the reference, clearly you can't, since there could be any number of references with different names, which one would the "self.getName()" return?
You could give each object a unique identifier, say at construction time. Then one of the arguments to new()
would be the object name, you would save it as self.name
(for example) and then you could access it as required (I would imagine, for log messages or lookup within some associative array). So you would do
my_stack = Stack:new("my_stack", 2,4)
my_stack:push("dog") -- my_stack.elements = {2,4,"dog"}
I am not aware of a way to make new()
figure out that the new instance is going to be assigned to a variable called my_stack
. In fact I suspect it is not possible not even with the debug module because the assignment will only take place once the new
has returned. So there is nothing forcing the name of the object to be the same as the variable, it's entirely up to you. It's not even something you want because, again, you could have multiple references to same stack object:
a = Stack:new("a", 2,4)
b = a -- b and a are the same object in memory
Should the error message mention a
or b
? I think it is better for you to assign an id to the object and then you always know which object is being talked about in an error message:
a = Stack:new("my_stack_1", 2,4)
b = a
t = { b = { c = a } }
a:push("dog") -- error will mention my_stack_1: clear which object you are referring to
t.b.c:push("dog") -- error will mention my_stack_1: still clear which object you are referring to
If you are worried that from the error message, you can't determine which line calls new(self, "dog")
, that's where the debug
module could come in handy: with it you can get the line number and file where the call is made, so you could say "object my_stack_1:pop(): no elements left in stack (called from line X of file Y)"
Upvotes: 5