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

[SOLVED] Help with pcall

Started by manu3d, 05 March 2014 - 11:55 PM
manu3d #1
Posted 06 March 2014 - 12:55 AM
Hi everybody, lua -and- computercraft newbie here.

I'm dealing with the following simple code, executed in a turtle, which is derived from the last example in this page: http://www.lua.org/pil/8.4.html


local status, err = pcall(function () error({code=121}) end)
print(status)
print(err)
print(err.code)

I'm confused by the result. Status is false, which make sense. But err is a string when I thought it'd be a table, and print(err.code) results in an empty line, consistent with err -not- being a table.

Am I doing something wrong or pcall does not return a table in ComputerCraft?

Manu
Edited on 07 March 2014 - 12:46 PM
theoriginalbit #2
Posted 06 March 2014 - 02:25 AM
The problem isn't what pcall returns, it's with what error returns1. ComputerCraft runs Lua 5.1 which tostring's the message. Unfortunately the feature of being able to provide anything other than a string as the message was introduced in Lua 5.2

1 pcall can return anything, try the following code

local ok, val = pcall(function() return {code=301} end)
print(val.code)
Edited on 06 March 2014 - 01:27 AM
manu3d #3
Posted 06 March 2014 - 08:40 PM
Thank you theoriginalbit for your answer!

Amazing how, having just started with lua, I managed to attempt to take advantage of one of the very latest features!

Concerning your workaround: my understanding is that the point of a pcall is that it catches errors and trigger special handling. I guess what you are saying is that if I want to do some error handling that includes passing back structured error information instead of a simple string I must bypass the error() function altogether. I.e. write functions that return an expected value or return something that can be interpreted and handled like an error by the calling function.


if(thereIsAnError) then
   return {errorCode=301, errorLevel="PANIC!", message="You attempted to reboot the universe without saving. Don't do that again."}
else
   return theExpectedNonTableValue
end

Am I understanding you correctly?
theoriginalbit #4
Posted 06 March 2014 - 11:20 PM
-snip-
it wasn't so much a workaround, as it was a snippet to show that pcall can return values.

I'd probably say the easiest method of dealing with the problem would be to just setup a variable to store error codes like so

local errorCode

local function foo()
  errorCode = {code=301; level="PANIC"}
  error("fatal error! what did you do?!")
end

local ok, err = pcall(foo)
if not ok then
  print(err)
  print("Code: ", errorCode and errorCode.code or "[missing data]")
  print("Level: ", errorCode and errorCode.level or "[missing data]")
end
manu3d #5
Posted 07 March 2014 - 01:34 PM
Of course! This way pcall still gets to do its job of catching errors while data about the error becomes available through the errorCode variable. Neat!

Also, to avoid potential conflicts or even store a history of errors, I guess I could do this:



local errorTable = {}

local function foo()
  if (anErrorArises) then
    errorTable[moreOrLessUniqueErrorKey] = {code=12; level="PANIC", message="Ouchy!!!"}
    error(moreOrLessUniqueErrorKey)
  else
    return aValue
  end
end

local ok, theReturnedValueOrAnErrorKey pcall(foo)
if not ok then
  local errorObject = errorTable[theReturnedValueOrAnErrorKey ]
  print(errorObject.code)
  print(errorObject.level)
  print(errorObject.message)
end


Thank you! Much appreciated!
Edited on 07 March 2014 - 12:37 PM
theoriginalbit #6
Posted 07 March 2014 - 02:28 PM
Also, to avoid potential conflicts or even store a history of errors, I guess I could do this
well there shouldn't be conflicts unless you plan on dealing with coroutines. however if you wanted to do a history you could simply do this


local errorCode = {}

local function foo()
  table.insert(errorCode, {code=301; level="PANIC"})
  error("fatal error! what did you do?!")
end

local ok, err = pcall(foo)
if not ok then
  print(err)
  print("Code: ", errorCode[#errorCode].code or "[missing data]")
  print("Level: ", errorCode[#errorCode].level or "[missing data]")
end