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;
}
}
_______________________________________________
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss