[Solved] How To Handle "tool Internal Errors"

Hello,

I’m struggling trying to get my head around something here. This is just about tidying up the code in vader, nothing absolutely essential or road-blocking. But an interesting problem. And I’m trying to be smart this time, generalizing everything as much as I possibly can.

Is there a smart way to generalize a sort of ‘tool internal’ error handling in Lua?

Currently I’ve got a number of functions that call a bunch of other functions, that call a bunch of other functions that call some other functions that… well, you get the idea. And for functions I’ve got a tool internal standardized return format of RETURN_VALUE, ERROR_MESSAGE, NOTES. The RETURN_VALUE is either nil/false (=error), in which case there is also an ERROR_MSG, or the actual return value, which is by definition true.The notes are something added to logs by the function, not really meaningful for the point here.

What I’m up against, is that I’m forced to handle each and every function call in every function that would handle errors (practically this should be every single one) with a repeating piece of code something like

  
local return_val, error_msg, notes = function(args)  
if not return_val then  
 return return_val, error_msg, nil  
elseif notes then  
 --handle notes   
 --with a bunch of   
 --lines that repeat every   
 --time  
 return return_val, nil, notes_handled  
end  
  

Basically this forms a ‘return chain’ that, if some function at some point returns false, passes all that back to a ‘main handler’ that will then display the error and halt execution and do some special dance or whatnought.
So. My question is: is there a way to wrap that block inside some neat, generalized (preferably global?) function that would handle the above situation where the wrapped function returns false/nil. It would then pass the return value again to the next caller(/hopefully a magical wrapper?). OR a way to return it directly to the ‘main handler’.

I’m aiming at something like:

  
my_special_assert(function, args)  
  

…that would skip the if, then, elseif, then, end -part in some strange way possibly involving hidden unicorn powers.

But I have zero knowledge if this is doable in Lua (or any other language for that matter)…?
So…halp.?

Answering my own question with a follow-up question here:
How No-No in a scale of 1 to 10 would it be to try and setup the first call in main handler as a coroutine, and yield to that point from any error confronted…? Would that even help?
I’ve never touched the concept of coroutines, but it suddenly struck me that they MAYBE could be useful here. As far as i know, they’re treated as not parallel running functions, but as sort of additional exit/enter points that can be freely placed within code.

EDIT:

Oh wow, it seems that the Lua coroutines are in fact designed to handle this exact type of situation. I think I’m going to have to study this stuff a bit deeper.

Yep. Got it. Consider the following testpad sketch:

Click to view contents
  
function main_handler()  
  
 --create coroutine thread  
 local first_call = coroutine.create(first_layer)  
  
 --execute coroutine thread, allocate values for error()  
 local success, errorz = coroutine.resume(first_call)  
  
 --display total WIN!  
 print(success, errorz)  
  
end  
  
function first_layer()  
  
 second_layer()  
 print("Oh noez. I'm never printed!")  
 return true  
  
end  
  
function second_layer()  
  
 third_layer()  
 print("Oh noez. I'm never printed!")  
 return true  
  
end  
  
function third_layer()  
  
 error("It's over now")  
 print("Oh noez. I'm never printed")  
 return true  
  
end  
  
  
--EXECUTE!  
main_handler()  
  
  

This solves my problem 100%. (EDIT: so does the pcall(), presented below…, much simpler) Going to edit thread title to make it more clear.

Just to note a maybe not so evident point: Lua has an internal command to raise an error on whatever code point the user wishes. The function for this is:

  
error(error_message)  
  

When this is called on a normal (non-coroutine) situation, it simply stops execution and pushes the error into terminal. However when this is called in a coroutine, the coroutine THREAD, which is run in something called ‘protected mode’(??) is stopped, and it gets a return value of false, with the error_message specified in error(error_message). This is mind-blowing stuff. Yiihaa!

Not sure if I understand correctly, but probably all you want/need is pcall or xpcall?

Wow. That is even more mind-blowing. Yes; that appears to skip the need for coroutine-shenaningans altogether, AND that also is exactly what I’m after. Seems I should probably take a minute, and rtfm…

Thanks!!

EDIT:

The above example with coroutines, done with pcall() - removes need for coroutines.

  
function main_handler()  
  
 --execute first function in protected mode, allocate values for error()  
 local success, errorz = pcall(first_layer)  
  
 --display total WIN!  
 print(success, errorz)  
  
end  
  
function first_layer()  
  
 second_layer()  
 print("Oh noez. I'm never printed!")  
 return true  
  
end  
  
function second_layer()  
  
 third_layer()  
 print("Oh noez. I'm never printed!")  
 return true  
  
end  
  
function third_layer()  
  
 error("It's over now")  
 print("Oh noez. I'm never printed")  
 return true  
  
end  
  
  
--EXECUTE!  
main_handler()  
  

A happy accident, though, is that I learned something about coroutines. :)

There is a downfall with pcalls though, because you can deliberately circumvent all errors and perhaps including very critical ones.
I don’t know if it is similar to writing a C-program and simply ignore errors that causes memory leaks and eventually crashes, but i would take that risk only take if i knew it is applicable to a situation which cannot be prevent any otherwise and where the problem cannot expand to catastrophic events.

Thanks for pointing that out. I’m a novice in programming so this is quality info.

I’m going to wrap the top-level function calls in pcall(). This will greatly simplify the problem of handling ‘tool internal’ errors. By those I mean in this case the situations where user input is invalid or just weird. Exiting the nested function pile with a simple error(“Ur doing it wrong!”) is a total life saver here. Just need to rework the code to suit that.

I think this will be immensely helpful for debugging too, as I can just catch the errors without stopping execution and won’t have to ‘Reload all tools’ or save the .lua-file with modifications after each of the millions and trillions of errors I get each time I wrestle the beast. I think your point concerns this? I’m not actually sure if I’ll run into problems with this method, but this will be a problem ONLY for the ‘Lua internal’ errors. Which I’m going to get rid of. To an extent… I hope.