idea: try/catch and "rethrow"...?

Allen Wirfs-Brock allen at wirfs-brock.com
Tue Feb 1 13:17:58 PST 2011


On Feb 1, 2011, at 11:52 AM, Mike Samuel wrote:
> 
> Do these problems go away if the stack trace is grabbed when the
> Throwable is constructed, not when it's thrown?
> 
> Java does this for java.lang.Throwable and it provides a
> fillInStackTrace() method to allow rethrowers to manually reset the
> stack trace to the throw point.
> 
> Java also allows for stackless exceptions via setStackTrace(new
> StackTraceElement[0]) which allows for pre-allocation of
> user-exceptions which for pragmatic reasons (imagine throwing an
> OutOfMemoryError because you ran out of space allocating the stack
> frame) shouldn't include stack.  This mitigates most of the
> inefficiency in using exceptions for control flow, and is used by Neal
> Gafter in his Java closures proposal to implement break/continue.
> 
Of course JavaScript doesn't have the concept of Throwable.  Any value can be thrown.

Also note that stacktrace properties on Error objects is not in the ECMAScript standard and personally I don't think it should be.

A debugger (or debugger infrastructure)  can capture stack trace information and maintain an association between a stack trace info and specific thrown objects.  Even if the object is thrown multiple times.  (BTW, this is probably a good use of Ephemeron tables.).  This information could even be reflected back to the JavaScript layer via an API that on-demand provides the stack trace info for a recently thrown error object.  But I really don't think stack-trace info should be automatically reified for every throw.  I think it should only happen if a debugger is active or if reflective debug support has been explicitly enabled.

You can probably get into a debate about about whether exceptions should be used for normal control flow purposes.  But they really are the only way in JavaScript to implement control flow that crosses function invocation  boundaries.  Because being a good host language is one of our goals keeping that style of throw as cheap as possible seems like something we should care about.

Throwing a known string value at a handler with a catch guard for that string should seem to be about as lightweight as you can get.  But sometimes (for example within a recursive function) you need a unique throw value and that probably means a new object..

If I was going to compile the following Smalltalk code to JavaScript:

lookFor: obj in: seq  "return the position of obj within a sequence "
    | position |
    position = 0.
    seq do: [:elen| elem == obj ifTrue: [^position]. positiion := position+1].
    ^ -1 

(note that code in brackets [ ] is essentially an anonymous function and ^ within such code returns from the surrounding method)

It would probably generate into something like the following

function loopForIn( obj, seq) {
    let __innerReturn = {};
    let __exitValue = __escape;
    try {
       let position = 0;
       seq.do(function(elem) {
           if (elem==obj) {
                 //this clause is what the ^ compilers into
                 if (__exitValue !== __innerReturn ) throw new cannotReturn();  //only one return allowed (not a full continuation)
                 __exitValue = position;  //probably cheaper than adding a property to __exit object
                throw __innerReturn;
           }
          position = position + 1;
      });
      return -1;
   } catch (e if e === __innerReturn) {
       return  __exitValue;
   }
}
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20110201/15719559/attachment.html>


More information about the es-discuss mailing list