try/catch

Hi,

Can anyone tell me if I am missing something with this code ?

Why is the exception not caught?

System.println("BEGIN");
var numberArray = [0, 0, 0];

try
{
  System.println("a");
  numberArray[4] = 1; 
  System.println("b");
}

catch (exception) {
  System.println("catch");
}

finally
{
  System.println("finally");
}

System.println("END");

The similator output the following :

BEGIN
a

Error: Array Out Of Bounds Error
Details: Failed invoking <symbol>


Note : I have tested using SDK 3.0.10 and 3.0.12.

Thanks

  • Because it’s not an exception, it’s a (fatal) error. There’s a few things like this in Monkey C which are fatal errors and can’t be caught. IIRC, another example is when you call toNumber() on a non-numerical string, at least on older devices. I wish it weren’t so, but I’m sure there are reasons for it to be this way.

    The downside is that if you deal with user input or fancy settings, you have to sometimes waste code validating certain things that would cause a fatal error in Monkey C, which is sort of redundant (the library code which triggers the fatal error is obviously checking the same thing that you will have to check — if only that error could be caught.)

    As a matter of fact, an array out of bounds error used to reboot old devices like 230, which could lead to an endless reboot loop. That bug’s been fixed now, but there’s no getting around the fact that errors like this will still cause your app to terminate. 

  • Thanks for the info. I wasn't aware! Would be nice if Garmin can change this behavior...

  • TBH I doubt they'll change it, and even if they did, they wouldn't update old devices like 230, 920XT, etc., so you'd still have to worry about it if you targeted old devices.

  • Not all things raise exceptions that can be caught, and those that do like likely say so in the api guide.  See Ble.registerProfile() as an example.

    That said, I tend to use try/catch pretty infrequently, for a few reasons.

    1) I use them for things that are recoverable, at least while debugging in shared code.  Doing Application.Properties.getValue() on a non existent key will raise an exception, but at early stages of an app, I might have a typo in the key and can supply a default in catch.

    2) they make the code larger and maybe a bit harder to read and follow.  If you've fully tested something, they may not be needed.

    3) when debugging, you're going to be pointed at where the problem occured, so they aren't really needed.  Putting in a println may be enough, and that's easier to remove/comment out when you're found the problem.

  • "because it is a fatal error not an exception".  This is true and people may feel comfortable with such a statement.  In fact, it is trivially true.  What is fatal is a design choice by Garmin.  I certainly agree that range checking errors should be fatal as this is a basic problem with design which needs fixing not masking.  Recoverable errors are usually associated with things outside of the programmers control such as obtaining a resource.  From memory the Comm module does not allow recovery from some things outside the programmers control such as a website returning badly formed JSON.

  • In the case off comm you mention, you should see that as the responseCode in the callback.

  • I've never used try/catch... so I looked this up here, and your comment popped up. Interestingly you mention getValue(). And all of a sudden my getValue() calls are throwing Unhandled Exceptions.I went in and changed the names of my Keys for User Settings in properites.xml. And now in my code, when I call Properties.getValue(), it aborts! Ugh. The Key Names are correct. And it runs fine in the simulator. I'd prefer to figure out the root cause, rather than enclose all my getValue() calls in try/catch blocks to band-aid these issues. Any idea why these would fail on a real device after changing the name of the Keys? I'm not even sure what I would put in the catch statement to work around an exception I can't explain.

  • try/catch doesn't help here because you have valid key

    use getValue only in initialize view/app and after onSettingChanged is called

    if you want to change the name of key leave the old one for few versions and start to use new one

    if you modify properties using setValue do it in app.onStop()

  • Thanks! But I am getting an "Unhandled Exception" in the CIQ_LOG.YML on getValue(). So shouldn't I be able to catch it?

    I want users to be able to actually adjust User Setting mid activity. There are lots of reasons this is valuable. For example, one setting is the intended distance of the ride. I update the projected finish time based on various dynamics of the ride. They might decide to change the ride distance mid ride. So I've been calling my getSettings() function on a regular basis. Sounds like I need to use onSettingChanged instead. But would that really fix this Key corruption issue? I don't use setValue()... I only getValue(), and get what users modify using Garmin Connect.

  • Bug is in system (inside getValue()) not in your code. I've tried many things and not avail.

    Read all settings into globals/members and use them.

    You can catch only  'named exception' e.g. 'InvalidKeyException'. You can't catch null*2 - it's also Unhandled exception, no more code is executed.