This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
skwerlman's profile picture

Find the name of a function

Started by skwerlman, 22 March 2014 - 05:42 AM
skwerlman #1
Posted 22 March 2014 - 06:42 AM
I know that this is possible using the Lua debug library, but it doesn't look like CC implements it. Anyone know of a way to do this without requiring each function to set a name string?
GopherAtl #2
Posted 22 March 2014 - 07:27 AM
nope. I think java functions give their names when you tostring() them, might just be certain built-in luaj functions, but nope, no getting lua function's names. They don't, strictly speaking, /have/ names, actually. Functions are first-class objects, the name is just a variable that references the function, and many variables can reference the same function.

The most common lua function syntax

   function <name> (<args...>)
	 <body>
   end

is actually syntactic sugar, a convenience and aesthetic thing. The "natural" lua syntax is

<name> = function(<args...>) <body> end
which makes the fact that the function name is just a variable holding the function more explicit.
Edited on 22 March 2014 - 06:30 AM
oeed #3
Posted 22 March 2014 - 07:33 AM
What's the context of what you're trying to do? There might be an alternate way to do it.

Alternatively, you could do something like this:

function myFunction()
	print('hi')
end
local func = myFunction --your reference to the function
for k, v in pairs(getfenv()) do
	--you could also use _G, checking if k ~= 'func' is a litte hacky, but it'll probably work
	if v == func and k ~= 'func' then
		--v is the function name
	end
end

It's a bit hacky, and it's not 100% sure to work, but it might.
Edited on 22 March 2014 - 07:49 AM
skwerlman #4
Posted 22 March 2014 - 08:28 AM
What's the context of what you're trying to do? There might be an alternate way to do it.

Alternatively, you could go something like this:


function myFunction()
	print('hi')
end
local func = myFunction --your reference to the function
for k, v in pairs(getfenv()) do
	--you could also use _G, checking if k ~= 'func' is a litte hacky, but it'll probably work
	if v == func and k ~= 'func' then
		--v is the function name
	end
end
Basically, I have a function that gets passed an arbitrary function. I want to find the name of the variable that contains the passed function, if there is one. It would also be nice if I could handle anonymous functions, too.

EDIT: Maybe iterate over _G until I find a match? I swear can read! Really, I can!
Edited on 22 March 2014 - 08:02 AM
Bomb Bloke #5
Posted 22 March 2014 - 08:43 AM
You could do that, but there's no guarentee you'll find one (most user-defined variables don't end up in there, global or not), or even a guarentee that the function was ever specifically assigned to a variable at all.

To guess, are you trying to create a script that "resumes" other scripts by recording what they did and "replaying" it later? Again, more context would make it easier to help you.
skwerlman #6
Posted 22 March 2014 - 08:56 AM
You could do that, but there's no guarentee you'll find one (most user-defined variables don't end up in there, global or not), or even a guarentee that the function was ever specifically assigned to a variable at all.

To guess, are you trying to create a script that "resumes" other scripts by recording what they did and "replaying" it later? Again, more context would make it easier to help you.
I'm trying to augment error messages in certain instances by not only specifying where the error occurred (as in the default scheme) but also what caused the error. Knowing the name of a function (again, if there is one) is important because I'd like to specify which of several functions (as in the below example) passed caused the error.

function foo( ... )
  local tFuncs = { ... }
  local tFuncNames
  for i=1, #tFuncs do
    --Insert code to find function name here
    tFuncNames = sFuncName -- where sFuncName is the name of the function
    assert(type(tFuncs[i]) == 'function', sFuncName..' is not a function')
  end
  --The rest of the code
end
GopherAtl #7
Posted 22 March 2014 - 09:03 AM
are you aware of pcall and the error function's ability to take a 2nd argument that is how many levels up to locate the error?

examples..


  function myFunc(args)
	error("You gave me bad args!",2)
   --the 2 makes it throw the error with the line number where myFunc was called
   --instead of the line number of this error() call
  end

and pcall can be used to intercept and re-throw errors in code you don't control (and so can't modify the error() calls on)

  res={pcall(somebodyElsesFunction,args)}
  if res[1] then
	--res[2] through res[#res] will be the returned values of somebodyElsesFunction,
    --to be used normally or whatever
  else
	--res[1] being false means an error, and res[2] is the error message
	error("error in somebodyElsesFunction : "..res[2],someLevel)
	--rethrow with level as in last example
  end
Edited on 22 March 2014 - 08:04 AM
skwerlman #8
Posted 22 March 2014 - 09:05 AM
are you aware of pcall and the error function's ability to take a 2nd argument that is how many levels up to locate the error?

examples..


  function myFunc(args)
	error("You gave me bad args!",2)
   --the 2 makes it throw the error with the line number where myFunc was called
   --instead of the line number of this error() call
  end

and pcall can be used to intercept and re-throw errors in code you don't control (and so can't modify the error() calls on)

  res={pcall(somebodyElsesFunction,args)}
  if res[1] then
	--res[2]-res[#res] will be the returned values of somebodyElsesFunction, to be used normally ot whatev)
  else
	--res[1] being false means an error, and res[2] is the error message
	error("error in somebodyElse'sFunction : "..res[2],someLevel)
	--rethrow with level as in last example
  end
Yes, I am, but I'd also like to give the name of the offending argument. As I said, I'm looking to improve the current error system.
GopherAtl #9
Posted 22 March 2014 - 09:08 AM
why would yo want to throw the name of the variable passed as an argument instead of the logical name of the argument it was passed as? if function foo(derp) errors for a bad derp, just throw "bad derp" with the error level such that it gives the line number where they called foo? surely the leap from derp to whatever variable they passed is not an unreasonable ask for the programmer?
Edited on 22 March 2014 - 08:10 AM
skwerlman #10
Posted 22 March 2014 - 09:16 AM
why would yo want to throw the name of the variable passed as an argument instead of the logical name of the argument it was passed as? if function foo(derp) errors for a bad derp, just throw "bad derp" with the error level such that it gives the line number where they called foo? surely the leap from derp to whatever variable they passed is not an unreasonable ask for the programmer?
Because sometimes, as in the example above, you don't know how many variables there are, and it may even be that the programmer is dynamically generating and passing the variables, so they don't even know, and then it's a debugging nightmare. If I could get the name, I could tell the programmer where to look with greater precision than otherwise, making their job that much easier.
oeed #11
Posted 22 March 2014 - 09:25 AM
Have you seen this? I haven't really seen how the code works, but it looks like it's along the lines of what you want.

http://www.computerc...-file-extracts/

Avoid posting because it's been dead almost a year now.
Edited on 22 March 2014 - 08:29 AM
skwerlman #12
Posted 22 March 2014 - 09:27 AM
Have you seen this? I haven't really see how the code works, but it looks like it's along the lines of what you want.

http://www.computerc...-file-extracts/

Avoid posting because it's been dead almost a year now.
That is so much better than what I was thinking. Great find!

EDIT: It appears to be broken… I can't seem to load any of the functions.
Edited on 22 March 2014 - 08:53 AM
skwerlman #13
Posted 22 March 2014 - 10:01 AM
@oeed: Your first idea works, and very well too. But, for whatever reason, it can't see functions declared as local, regardless of getfenv's scope. I'm gonna see if it works with other data types.

EDIT: It works with all variables, but with the same restrictions. It can't see local variables.
Edited on 22 March 2014 - 09:04 AM