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
  • > Notice how the stack trace show `source\Test\ClassThatIsNotUsedAnywhere.mc:3` as the source for the exception.

    This is a known issue. It is possible for errors inside the VM to be flagged as if they come from the last function in the assembly.

    The following does not work: return new self("foo");

    That is because this is not Java. The error message tells you that it expects to see a semicolon, but it found an open paren. This is because the expression `self(...)` is not valid in the MonkeyC language. Inside a static function the self object isn't even valid, so you shouldn't even be able to reference that name.

    > Triggers no error during automatic build, but causes this during the app run:

    Yeah, that should not compile either. That said, the runtime error message you get tells you exactly what the error is,, UnexpectedTypeException: Expected Class definition, given Object. You are passing an object (self is an implicit object of the type of the class for non-static functions, and should be invalid in a static function).

    > I can life with the workaround of putting the exception in a variable before throwing it.

    You should not have to do so now that you've fixed your code to not use an illegal reference to self.

Comment
  • > Notice how the stack trace show `source\Test\ClassThatIsNotUsedAnywhere.mc:3` as the source for the exception.

    This is a known issue. It is possible for errors inside the VM to be flagged as if they come from the last function in the assembly.

    The following does not work: return new self("foo");

    That is because this is not Java. The error message tells you that it expects to see a semicolon, but it found an open paren. This is because the expression `self(...)` is not valid in the MonkeyC language. Inside a static function the self object isn't even valid, so you shouldn't even be able to reference that name.

    > Triggers no error during automatic build, but causes this during the app run:

    Yeah, that should not compile either. That said, the runtime error message you get tells you exactly what the error is,, UnexpectedTypeException: Expected Class definition, given Object. You are passing an object (self is an implicit object of the type of the class for non-static functions, and should be invalid in a static function).

    > I can life with the workaround of putting the exception in a variable before throwing it.

    You should not have to do so now that you've fixed your code to not use an illegal reference to self.

Children
No Data