Complete
over 4 years ago

Custom Exceptions are broken or mis-documented (Monkey C, SDK and/or documentation bug)

Hello,

I just wanted to write a custom exception and stumbled across this bug.

Starting with the documentation here: https://developer.garmin.com/connect-iq/monkey-c/exceptions-and-errors/#creatinganexception

Code example from there:

class AppSpecificException extends Lang.Exception {
    //! Constructor
    //! @param msg Message explaining cause
    function initalize(msg) {
        Exception.initialize();
        self.mMessage = msg;
    }
}

(great code formatting works neither here nor there. please fix that)
Problems with the above code:
  1. It misses the import for `Toybox.Lang`, so it does not work properly out of the box. Please fix.
  2. It triggers a build warning: `Class 'AppSpecificException' does not initialize its super class, 'Exception'`
    Which can neither be fixed by calling `Lang.Exception.initialize();` instead of `Exception.initialize();`.
    Please fix.
  3. When the exception is used with a message (`throw new AppSpecificException("foo");`) it triggers this error:
     
    Error: Too Many Arguments Error
    Details: Failed invoking <symbol>
    Stack: 
      - initalize() at AppSpecificException.mc:8 0x1000133b 

    This one only disappears if you initialize the exception without a message (`throw new Lang.AppSpecificException();`), which kinda defeats the purpose of it all.
    Please fix.
  4. If you just deleted the body of the custom exception in hope of the parent have the correct default behavior, the code goes completely rouge and shows the "Too many arguments" error with a backtrace, that starts right, but the triggering file for the error might be some code, that is not even called or included anywhere.

This also is true, if you do not extend `Toybox.Lang.Exception`, but an exception that already has multiple constructor arguments like `Toybox.Lang.UnexpectedTypeException`.
Also if you call `new Toybox.Lang.UnexpectedTypeException("ss")`, so with too less arguments, the same error is triggered, although there are not **too many**, but **less than needed** arguments given. This is just confusing. Please fix.

Also hard-coded user path in error messages? I'll talk to that rayburn guy ;)

Error: Not Enough Arguments Error
Details: Failed invoking <symbol>
Stack: 
  - initialize() at /Users/rayburn/projects/toolchain5/mbsimulator/submodules/technology/monkeybrains/virtual-machine/api/Lang.mb:1457 0x30002cc4

Another thing, that is besides the point, but also a problem: it is not possible to have exception factories, because `throw` seems to want to have a fresh `class definition`, with `new` and everything.

Example:

using Toybox.Lang;

class UnknownTypesException extends Lang.Exception {
    public static function create() {
    	return new self();
    }
}

throw UnknownTypesException.create();

So the TL;DR:

  1. Please update the documentation
  2. SDK does not trigger wrong warnings for parents of exception not being initialized
  3. Custom Exceptions can not have messages
  4. Compiler goes rouge if custom exception does not have an initializer
  5. (after the above) Please make exception factories a thing :)

If you need anything, please feel free to contact me :)

--- Update 1

Correct the error message in Number 2

Former Member
Former Member
Parents
  • Here's what I meant when you could just let the caller handle a type error without using exceptions:

     enum {
     	tNumber,
     	tFloat,
     	tString,
     	tUnknown
     }
     
     function typeOf(o) {
     	var ret=tUnknown;
     	if(o instanceOf Number) {ret=tNumber;}
     	else if(o instanceOf Float) {ret=tFloat;}
     	else if(o instanceOf String) {ret=tString;}
     	return ret;
     }

Comment
  • Here's what I meant when you could just let the caller handle a type error without using exceptions:

     enum {
     	tNumber,
     	tFloat,
     	tString,
     	tUnknown
     }
     
     function typeOf(o) {
     	var ret=tUnknown;
     	if(o instanceOf Number) {ret=tNumber;}
     	else if(o instanceOf Float) {ret=tFloat;}
     	else if(o instanceOf String) {ret=tString;}
     	return ret;
     }

Children