Better exception handling

General discussion about LÖVE, Lua, game development, puns, and unicorns.
DSGuy
Prole
Posts: 1
Joined: Fri Dec 29, 2017 5:03 am

Better exception handling

Post by DSGuy »

Will love 0.11 improve exception handling? I hate how a game gets terminated just because if a missing audio file.
I have been trying to working around it with love.errhand and lua's error handler, unfortunately it's not your typical try, catch, and finally function, I tried xpcall, pcall and etc, but they are just so confusing.

Edit What I was actually considering was to make audio optional for the mobile user, because it becomes quite large with music. What I could have just done instead is to distribute the game (.love) with different versions (with or without audio), thanks for the reply
Last edited by DSGuy on Fri Dec 29, 2017 5:57 pm, edited 1 time in total.
User avatar
ivan
Party member
Posts: 1911
Joined: Fri Mar 07, 2008 1:39 pm
Contact:

Re: Better exception handling

Post by ivan »

pcall can handle that error:

Code: Select all

function love.audio.pNewSource(filename, type)
  local ok, res = pcall(love.audio.newSource, filename, type)
  return ok and res -- returns nil when "newSource" fails
end
But then you have to check if the function returns nil which can too verbose for some people.
User avatar
Tricky
Citizen
Posts: 75
Joined: Thu Dec 18, 2014 4:07 pm
Location: Breda, the Netherlands
Contact:

Re: Better exception handling

Post by Tricky »

I gotta admit it took me awhile to get used to Lua's exception handler myself.
Ivan has set up the "official" way to do it in Lua, and maybe also the quickest (and CPU wise fastest) way too.

If some extra debugging is in order you can also put it in like this:

Code: Select all

function love.audio.pNewSource(filename, type)
  local ok, res = pcall(love.audio.newSource, filename, type)
  if not ok then print("ERROR!",res) end
  return ok and res -- returns nil when "newSource" fails
end
Would "res" normally contain the actual returned resource it will now contain the error message and will this way be printed to stdout. If loading audio fails, you can then at least see why, even though the game won't crashout.
One downside though is that the traceback is not included this way, only the file name and the line number where the error was caused. Which can in a simple 'asset not found' issue be all the information you need, but in more complex situations be a bit bothersome. (Although now that I think about it, would that in this case be the filename and line number where the pcall itself was done? Oh well).


To truly find out how pcall works, I recommend you to download a cli based lua interface. It's very minimal, only contains the basic Lua functions. And try to type this in that cli interpreter.

Code: Select all

function GOOD() return "Hello World" end
function BAD() return Hello..World end -- This is a nil concat and thus will cause an error
Well that being done you can try this.

Code: Select all

ok,res = pcall(GOOD)
print(ok,res)
Results to "true Hello World"
ok contains "true" as an indicator the pcall had no errors. As I instructed to return "Hello World" I got what I wanted.

Now the BAD() routine

Code: Select all

ok,res = pcall(BAD)
print(ok,res)
The result will be

Code: Select all

false	stdin:1: attempt to concatenate a nil value (global 'Hello')
ok is now false to indicate there was an error, and "res" which would normally contain the outcome will now contain the error message.

If you call functions with parameters you just add them as parameters for pcall.

Code: Select all

-- Crash if in error
a = MyFunction("My Parameters",3,4,false)

-- Catched in pcall
ok,a = pcall(MyFunction,"MyParameters",3,4,false)
This works for all errors caused or handled by Lua.
I hope this fully shone a light on how the Lua error handler works.

I also think that it will not be fruitful if Löve would try to introduce any more sophisticated, as I'm afraid that would require to change some core Lua features. And since Lua is a 3rd party element in the Löve project, it's not always a wise thing to change that (it can get you a bit in trouble if new versions of that element come out. I got experience on that one).


(P.S. If you wanna know how to shut down the Lua CLI editor. Just use the command "os.exit()" ;) )
User avatar
zorg
Party member
Posts: 3441
Joined: Thu Dec 13, 2012 2:55 pm
Location: Absurdistan, Hungary
Contact:

Re: Better exception handling

Post by zorg »

First, at least it doesn't flat out crash (for that, anyway) but gives you a lövely baby-blue screen of death that details tons of info about what went wrong, most of the time. :3

Second, on the offchance that i might seem a bit unhelpful (and rude), let me provide you a small insight that might come as some kind of a relevation:

You do not ship a game that has errors like that.

Now, this is more for the developer of said löve project, if you only wanted to play someone else's game and it errored, then naturally, it's not your fault.

That said, as a developer, usually you want to see issues like that reported as errors so you can fix them; hiding them away doesn't fix anything. Why wouldn't you make sure that the game works on supported systems without relatively small issues like missing files / wrong filepaths?

The fact you cannot resume the state is due to most things not allowing you to resume state in this fashion (unless it's coded in, which takes tons of effort) Even something trivial (in the sense that the game could function without it) like music or sound effects needing tons of scaffolding code if you want to leave functions all over the place as you want to, should not be suprising. Last i seen a continue button in an application was in Windows 3.1 and even that didn't always work, and it was more magic than you'd probably want it to be.

But let me also offer some other solutions:

1. Easy but Hackish

Code: Select all

local empty_sound = love.sound.newSoundData(1,44100,16,1)
function myLoadMusicFunction(path)
    if love.filesystem.isFile(path) then
        return love.audio.newSource(path)
    else
        return love.audio.newSource(empty_sound)
    end
end
This will guarantee that you'll have a source, whether or not the file was found, no other method done on the returned Source object will error (probably), but you can take silence to mean that something went wrong.

2. "The usual"

What Ivan already posted above.

3. Hard

Implement hot-reloading.

This one is very complex, unique to what you are coding, and to what you want to accomplish, and probably unneeded, and will waste your time implementing this rather than your project proper. Then again, there is a chance that one would benefit from such system, since this would mean you wouldn't need to always reload everything.
Downsides would be diminished processing speed, at least. (wrapping most things into an xpcall does have its penalties, even if it's only done on one level / with one function)
And yes, i have made an implementation of this before, and i'm not even sure if it worked 100% correctly myself.

If your biggest issue, and the point of this post, was that you needed to restart your game any time you made an error, then by all means go with solution #3, though it might take you more time (and will cause more errors) than you'd care for.

Edit: Also, just to mention it, others before had issues with the BBSOD that löve provides as well, though their issue was that it wasn't user-friendly enough, so they customized the error-handler to be animated, have a button that when clicked, opened (or tried to open) the mail application with a message loaded in regarding the error, or sent an email itself using SMTP or whatever else; just wanted to show that there are many ways to approach one thing.
Last edited by zorg on Fri Dec 29, 2017 1:36 pm, edited 1 time in total.
Me and my stuff :3True Neutral Aspirant. Why, yes, i do indeed enjoy sarcastically correcting others when they make the most blatant of spelling mistakes. No bullying or trolling the innocent tho.
drunken_munki
Party member
Posts: 134
Joined: Tue Mar 29, 2011 11:05 pm

Re: Better exception handling

Post by drunken_munki »

I'm going to argue something that you might not want to here, so bear with me.
I hate how a game gets terminated just because if a missing audio file.
Well in my view this isn't an 'exception' that needs to be handled. This is bad programming. A simple file check that it exists can test if the file is there. If not, then the file should not be played and you can even spit out a critical error message. This could be done on a boot-up function that checks the data, or when the sound is played i.e. wrapped into a helper function that checks the file.

Why would you want to weave a complex 'exception handling' system for something that can be trivially handled, something that we expect in normal routine. Checking a file exists is a normal logical expected task, not an exception.

Now reading a file that may be broken, yes this is a danger. Which is why core functions handle these situations and return you an error message. In mid to top level coding, I would argue the point that you don't need this type of thing.

I have 98 thousand lines of code in my game that I have spent 3 years full time working on and I don't have a single example of exception handling, I can't even think of an example. This entire topic falls under 'code smells' and it comes from the OO/JAVA era of programming.


Secondly, in my view the blue screen error is the best way to go. Hiding your bugs, errors, and so forth under handlers is a terrible habit that will in the mid to long term cultivate a host of issues that you haven't seen or dealt with. Of course checking if things exist and piping out error messags is fine, I do it to; but in rare/specific instances.


You can feel free to disagree, I may be a lone voice on this but there you are.
User avatar
Tricky
Citizen
Posts: 75
Joined: Thu Dec 18, 2014 4:07 pm
Location: Breda, the Netherlands
Contact:

Re: Better exception handling

Post by Tricky »

I have to agree with zorg, that if you should not ship out games which can cause an error, and indeed if they do (we are all humans making mistakes and the ultimate way to find out if software is bug-free is making it meet the user), the information on that Blue Screen of Death, is mostly essential. I've used that information a lot in fixing bugs in my own projects. In Lua engines I created myself I've also deliberately put similar screens with full error information in stead of trying all kinds of crazy things to make the game carry on like nothing happened (only causing effects I didn't want never finding out why). Some players of those games of mine have often screenshot these error pages and quite often these screenshots did provide me all the information I needed to get the issue fixed.

Of course, I've quite often worked with "optional assets" myself. Particularly when it comes to music, allowing me to cut it from the game without having to change code, and sometimes for plain "dirty code". I basically only recommend that way for people who know what they are doing, though as bugs caused this way can be hard to fix.
User avatar
ivan
Party member
Posts: 1911
Joined: Fri Mar 07, 2008 1:39 pm
Contact:

Re: Better exception handling

Post by ivan »

Zorg is correct in theory.
While debugging, I also run strict.lua without pcall-s.
Nevertheless, similar errors still slip by due to bad packaging, delayed loading, etc.
In reality, production code is another story and there are many factors involved.
For example, if you have automated error reporting then you don't necessarily need to show an error message on the screen but I digress.
User avatar
Tricky
Citizen
Posts: 75
Joined: Thu Dec 18, 2014 4:07 pm
Location: Breda, the Netherlands
Contact:

Re: Better exception handling

Post by Tricky »

I think that even automated error reporting can sometimes need to throw an error. Some errors just cannot allow software to go on (unless you want your user to suffer). :)
Unremarkable
Prole
Posts: 1
Joined: Mon Apr 30, 2018 8:35 am

Re: Better exception handling

Post by Unremarkable »

Interesting topic. I've just released an app recently with a löve component and it allows the user to program buttons. One of the things the user can do is add an action to a button to play a sound effect. If they mis-type the file name of the sound file, then the app shouldn't crash!
pcall did the trick :awesome:

I only discovered löve recently and was impressed at how quickly I could get things running on Mac, Windows AND Linux - surprising how many other frameworks can't do that!
sherlockholmes221b
Prole
Posts: 4
Joined: Tue Oct 01, 2019 4:44 am

Re: Better exception handling

Post by sherlockholmes221b »

drunken_munki wrote: Fri Dec 29, 2017 1:24 pm I'm going to argue something that you might not want to here, so bear with me.
I hate how a game gets terminated just because if a missing audio file.
Well in my view this isn't an 'exception' that needs to be handled. This is bad programming. A simple file check that it exists can test if the file is there. If not, then the file should not be played and you can even spit out a critical error message. This could be done on a boot-up function that checks the data, or when the sound is played i.e. wrapped into a helper function that checks the file.

Why would you want to weave a complex 'exception handling' system for something that can be trivially handled, something that we expect in normal routine. Checking a file exists is a normal logical expected task, not an exception.

Now reading a file that may be broken, yes this is a danger. Which is why core functions handle these situations and return you an error message. In mid to top level coding, I would argue the point that you don't need this type of thing.

I have 98 thousand lines of code in my game that I have spent 3 years full time working on and I don't have a single example of exception handling, I can't even think of an example. This entire topic falls under 'code smells' and it comes from the OO/JAVA era of programming.


Secondly, in my view the blue screen error is the best way to go. Hiding your bugs, errors, and so forth under handlers is a terrible habit that will in the mid to long term cultivate a host of issues that you haven't seen or dealt with. Of course checking if things exist and piping out error messags is fine, I do it to; but in rare/specific instances.


You can feel free to disagree, I may be a lone voice on this but there you are.
Hiding bugs is not always bad. If the game is in its final version, it's better to show "Sorry, the game crashed. Please inform the developer", than "main.lua-38: Attempt to perform arithmetics on global 'variable' (nil value)'".In my opinion, the best way for handling bugs is to have global. unique _DEBUG variable, which, if set to true, shows whole error messages. Otherwise it should show only "Sorry for crash" message. Then you should just attach logging things to .txt or .log file (I recommend. It's very helpful for debugging since you don't need to error everything) and voila! The only thing you should be aware of is the error in this code. If you do something bad, you can have some trouble with debugging later.
Post Reply

Who is online

Users browsing this forum: No registered users and 172 guests