#1418 js: catch block rethrows different thing

vkuzkokov Sun 20 Feb 2011

Here's short example

@Js
class Main
{
  Void main()
  {
    try
    {
      echo("hi")
    }
    catch (MyErr e) { /*ignore*/ }
  }
}
@Js
const class MyErr : Err
{
  new make(Str msg) : super(msg) {}
}

I wanted to focus on a catch block generated:

catch ($_u0)
{
  $_u0 = fan.sys.Err.make($_u0);
  if ($_u0 instanceof fan.jsTest.MyErr)
  {
    var e = $_u0;
    var e;
  }
  else
  {
    throw $_u0;
  }
}

So if we catch some internal error, we throw an instance different from the one we actually got. Here's proposed patch:

diff -r 2f3486b59970 src/compilerJs/fan/ast/JsStmt.fan
--- a/src/compilerJs/fan/ast/JsStmt.fan Wed Feb 16 17:09:50 2011 -0500
+++ b/src/compilerJs/fan/ast/JsStmt.fan Mon Feb 21 00:26:28 2011 +0600
   private Void writeCatches(JsWriter out)
   {
     var := support.unique
+    orig := var
     hasTyped    := catches.any |c| { c.qname != null }
     hasCatchAll := catches.any |c| { c.qname == null }

     out.w("catch ($var)").nl
     out.w("{").nl
     out.indent
-    if (hasTyped) out.w("$var = fan.sys.Err.make($var);").nl
+    if (hasTyped) {
+      if (!hasCatchAll) var = support.unique
+      out.w("$var = fan.sys.Err.make($orig);").nl
+    }

     doElse := false
     catches.each |c|
@@ -324,7 +328,7 @@
       out.w("else").nl
       out.w("{").nl
       out.indent
-      out.w("throw $var;").nl
+      out.w("throw $orig;").nl
       out.unindent
       out.w("}").nl
     }

andy Mon 21 Feb 2011

The catch clause works in conjunction with fan.sys.Err.make - if the exception is already a Fan type, its returned, a new instance is not created. A new instance is created only if the the exception was native and needs to be wrapped in a Fantom type.

vkuzkokov Mon 21 Feb 2011

What if it doesn't need to be wrapped? The problem is that Err.make saves only error message losing any other properties of caught Error.

andy Mon 21 Feb 2011

It has to be wrapped so its a valid Fantom object. Is there a particular property you're interested in? Can we just fix that code to properly wrap with a Fantom Err type?

brian Mon 21 Feb 2011

Side note: originally in Java/C# everything subclassed a single fan.sys.Obj class. Then in Dec 2009 when we switched to value types, we built out infrastructure to support classes like Boolean, Long, etc natively. As part of that, I've always wanted to switch fan.sys.Err to be a subclass of RuntimeException so that we extend rather than wrap native exceptions. This idea is captured in ticket 717. But at this point it is a pretty big breaking change to Java code (and its a huge project), so I am a bit wary of doing it.

vkuzkokov Mon 21 Feb 2011

Properties I'm most interested in are rhinoException and javaException. BTW, why can't we in fact wrap the Error and give access to it via something like err->jsErr?

andy Mon 21 Feb 2011

The big problem is we don't have JavaScript FFI yet - so you can't use that object directly from Fantom code. Thats what really makes this all a bit tricky.

If you need to workaround that right now - you can always use a native method and have full access however you needed.

vkuzkokov Mon 21 Feb 2011

This workaround is not always applicable. Here's scenario:

  • Some JavaScript Error is thrown
  • Any catch block inside another pod wraps this Error to sys::Err
  • Now I get sys::Err and can't retrieve the information I need.

Login or Signup to reply.