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

Mike Samuel mikesamuel at gmail.com
Tue Feb 1 13:42:07 PST 2011


2011/2/1 Allen Wirfs-Brock <allen at wirfs-brock.com>:
>
> 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.

I wasn't arguing that it should always be available.  Stack
introspection is abused in nasty ways in java and has made it hard to
spec things like tail-call opts, but it also enables fine grained
logging and statistical profiling which are often things one wants to
be able to turn on in production.

The argument I was trying to make was that stacks derived at construct
time are better semantically than stacks derived at throw time.


> 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

An ephemeron table can't associate a stack with a selfless value, so
ephemeron tables don't close the non-Error value hole.

One way to close it is to wrap the thrown value in an envelope that
can carry stack info, and then associate that envelope with the catch
block that handles the exception.  The base error class could just be
a type that captures stack info at creation time and so doesn't need
an envelope.


> 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;
>    }
> }


More information about the es-discuss mailing list