Conditional catch clause

# Claude Pache (6 years ago)

Hello,

In SpiderMonkey (and perhaps other JS engines?), there are conditional catch clauses:

catch (exception if condition)

Could such a feature added to ECMAScript?

Rationale: Although try/catch mechanism was initially intended for treating errors, it could be used in normal control flow with non-error condition. ES.next sanction this pattern with StopIteration. In this case, it would be nice to have a catch clause listening only what is wanted, without having to add code for filtering out and rethrowing. Here is an example of use:

Map.prototype.some = function(f, o) {
	var ok = {} // an arbitrary private object
	try {
		this.forEach(function(v, k, m) {
			if (f.call(o, v, k, m))
				throw ok
		})
	}
	catch (e if e === ok) {
		return true
	}
	return false
}

instead of, e.g.,

	catch (e) {
		if (e !== ok)
			throw e
		return true
	}

It is arguably not an important feature, but it is a nice one. Note also that the "if condition" construct is the same as in array comprehension (I want to say: it is not "yet another syntax").

Claude

# David Bruant (6 years ago)

Le 19/12/2012 14:13, Claude Pache a écrit :

Hello,

In SpiderMonkey (and perhaps other JS engines?), there are conditional catch clauses:

catch (exception if condition)

Could such a feature added to ECMAScript?

Rationale: Although try/catch mechanism was initially intended for treating errors, it could be used in normal control flow with non-error condition.

Why not just use normal control flow when you want to express non-error conditions? throw/try/catch was indeed intented for treating errors and when I read code, I expect an error path when encountering a try/catch.

ES.next sanction this pattern with StopIteration. In this case, it would be nice to have a catch clause listening only what is wanted, without having to add code for filtering out and rethrowing. Here is an example of use:

Map.prototype.some = function(f, o) { var ok = {} // an arbitrary private object try { this.forEach(function(v, k, m) { if (f.call(o, v, k, m)) throw ok }) } catch (e if e === ok) { return true } return false }

instead of, e.g.,

  catch (e) {
  	if (e !== ok)
  		throw e
  	return true
  }

I don't see the benefit from your example. You're basically removing one or 2 lines of code in an hardly more expressive way. Your above example could even be rewritten as:

     catch (e) { if (e !== ok) throw e
         return true
     }

That could be a code convention without needing to be part of the language.

Do you have example of code in the wild that would benefit (performance, readability, etc.) from such an addition?

# Claude Pache (6 years ago)

Le 19 déc. 2012 à 15:32, David Bruant <bruant.d at gmail.com> a écrit :

Le 19/12/2012 14:13, Claude Pache a écrit :

Hello,

In SpiderMonkey (and perhaps other JS engines?), there are conditional catch clauses:

catch (exception if condition)

Could such a feature added to ECMAScript?

Rationale: Although try/catch mechanism was initially intended for treating errors, it could be used in normal control flow with non-error condition. Why not just use normal control flow when you want to express non-error conditions? throw/try/catch was indeed intented for treating errors and when I read code, I expect an error path when encountering a try/catch.

As I've said, iterators throw StopIteration, which may be considered as a non-error. And in the code example I've given below, I can't use "normal" control flow to stop forEach from iterating over the remaining values, but throwing works fine. It is not written in stone that throw/try/catch must be used only for what it was primarily intended for.

ES.next sanction this pattern with StopIteration. In this case, it would be nice to have a catch clause listening only what is wanted, without having to add code for filtering out and rethrowing. Here is an example of use:

Map.prototype.some = function(f, o) { var ok = {} // an arbitrary private object try { this.forEach(function(v, k, m) { if (f.call(o, v, k, m)) throw ok }) } catch (e if e === ok) { return true } return false }

instead of, e.g.,

  catch (e) {
  	if (e !== ok)
  		throw e
  	return true
  }

I don't see the benefit from your example. You're basically removing one or 2 lines of code in an hardly more expressive way. Your above example could even be rewritten as:

   catch (e) { if (e !== ok) throw e
       return true
   }

That could be a code convention without needing to be part of the language.

Do you have example of code in the wild that would benefit (performance, readability, etc.) from such an addition?

David

I haven't search if there are code in the wild that would benefit, and in any case, the benefit would indeed be small (slightly less code and better readability), but I didn't see counterindications against that syntax either.

Claude

# Brandon Benvie (6 years ago)

Another benefit is in not polluting the stack trace for actual errors, which is actually a pretty big annoyance now for control flow try...catch wrappers like for of shims.

# David Bruant (6 years ago)

Le 19/12/2012 16:38, Claude Pache a écrit :

Le 19 déc. 2012 à 15:32, David Bruant <bruant.d at gmail.com> a écrit :

Le 19/12/2012 14:13, Claude Pache a écrit :

Hello,

In SpiderMonkey (and perhaps other JS engines?), there are conditional catch clauses:

catch (exception if condition)

Could such a feature added to ECMAScript?

Rationale: Although try/catch mechanism was initially intended for treating errors, it could be used in normal control flow with non-error condition. Why not just use normal control flow when you want to express non-error conditions? throw/try/catch was indeed intented for treating errors and when I read code, I expect an error path when encountering a try/catch. As I've said, iterators throw StopIteration, which may be considered as a non-error.

I completely agree. I have said elsewhere [1] that StopIteration could be its own statement. What we want is a way to stop the current call frame. The language provides 2 such ways, return and throw. Return can't be used because it may result in ambiguities. It could be the same thing for throw, but normal use of throw make that throwing a specific object is an acceptable hack on StopIteration.

And in the code example I've given below, I can't use "normal" control flow to stop forEach from iterating over the remaining values, but throwing works fine.

The problem lies in the "bad" forEach design. Arguably every/some may be more what you want if stopping after some element is a normal thing in your program. It's barely more hacky. Arguably, you could create a different array and apply forEach on this secondary with .filter.forEach. This may have some performance issue.

In any case, that's more of a hack than an actual throw.

David

[1] esdiscuss/2012-November/026639

# David Bruant (6 years ago)

Le 19/12/2012 16:45, Brandon Benvie a écrit :

Another benefit is in not polluting the stack trace for actual errors, which is actually a pretty big annoyance now for control flow try...catch wrappers like for of shims.

This is making me realize that maybe the language needs a third way to end a frame. This third way wouldn't propagate as throw does but would be used only as a communication mechanism between the engine and a user-defined function. Maybe "break"?

In an iterator, one would express "break StopIteration" to stop the iteration. In a .forEach, one would write "break StopIteration" to stop the iteration. What I'm describing might be violently backward incompatible (and doesn't behave well inside switch statement and in cases where there are labels), but I find the thought experiment interesting.

# Brandon Benvie (6 years ago)

The magical quality that throw has is its ability to end multiple call frames at once. Much like a second continuation channel, or the error channel in a promise, it escapes past any number of listeners on the normal channel, only stopping at the first listener on the error channel.

# John J Barton (6 years ago)

On Wed, Dec 19, 2012 at 8:11 AM, Brandon Benvie <brandon at brandonbenvie.com>wrote:

The magical quality that throw has is its ability to end multiple call frames at once. Much like a second continuation channel, or the error channel in a promise, it escapes past any number of listeners on the normal channel, only stopping at the first listener on the error channel.

Well said: it's always possible to argue for 'goto' in specific cases. With experience we've learned that these seemingly sensible features have debilitating system effects.

The mistake of including StopIteration should not be used to justify including more mistakes.

Communicating two different non-error results through the normal return channel is not easy, but mixing one of the non-error results with errors and sending them both through the error channel is not a solution, it's just a hack.

jjb

# Herby Vojčík (6 years ago)

Brandon Benvie wrote:

The magical quality that throw has is its ability to end multiple call frames at once. Much like a second continuation channel, or the error channel in a promise, it escapes past any number of listeners on the normal channel, only stopping at the first listener on the error channel.

Yes. The problem is, it is only one global channel. Thus, all exception sent down to it can be in different contexts, but must be multiplexed into that one channel.

For example in Amber, non-local returns are emulated via throw. A try is cheap, but catch is expensive, so when non-local return happens nested in five more methods that also include non-local return, five catch/rethrow happens.

So to answer David's questoin, this is definitely a case for something_like conditional catch clause.

But these channels are better idea. I think we may have multiple exception-like channels. One is present by default (the classical throw/catch), but one could have more parallel ones.

Then I can assume throw foo is the sugar for Reflect.errorChannel.raise(foo). And syntax of try could be enhanced to, say:

try(channel) { .... } catch (ex) { .... } finally { ... }

Then normal try {... is sugar for try(Reflect.errorChannel) {....

And one could simple let myChannel = new TryCatchChannel(); and use it. It can have some minimal api, like

channel.raise(exception); channel.pass(); // this does not break the original stack

and others are also interesting, but are probably beyond any simple proposal, like:

channel.defaultHandler = ex => console.log("Unhandled: "+ex); channel.resume(returnValueFromRaise); //fail if no raise is actually handled

etc.

Herby

P.S.: Maybe this could already be done with generator magic and yield; I did not research.

# Brendan Eich (6 years ago)

David Bruant wrote:

Le 19/12/2012 14:13, Claude Pache a écrit :

Hello,

In SpiderMonkey (and perhaps other JS engines?), there are conditional catch clauses:

catch (exception if condition)

Could such a feature added to ECMAScript?

Rationale: Although try/catch mechanism was initially intended for treating errors, it could be used in normal control flow with non-error condition. Why not just use normal control flow when you want to express non-error conditions?

Because you have to remember to re-throw in the "default" case (which is easy to forget).

# Brendan Eich (6 years ago)

David Bruant wrote:

Le 19/12/2012 16:38, Claude Pache a écrit :

Le 19 déc. 2012 à 15:32, David Bruant <bruant.d at gmail.com> a écrit :

Le 19/12/2012 14:13, Claude Pache a écrit :

Hello,

In SpiderMonkey (and perhaps other JS engines?), there are conditional catch clauses:

catch (exception if condition)

Could such a feature added to ECMAScript?

Rationale: Although try/catch mechanism was initially intended for treating errors, it could be used in normal control flow with non-error condition. Why not just use normal control flow when you want to express non-error conditions? throw/try/catch was indeed intented for treating errors and when I read code, I expect an error path when encountering a try/catch. As I've said, iterators throw StopIteration, which may be considered as a non-error. I completely agree. I have said elsewhere [1] that StopIteration could be its own statement. What we want is a way to stop the current call frame. The language provides 2 such ways, return and throw. Return can't be used because it may result in ambiguities. It could be the same thing for throw, but normal use of throw make that throwing a specific object is an acceptable hack on StopIteration.

This is a red herring. It's very rare to have to catch StopIteration.

The catch (e if cond) syntax is in SpiderMonkey and Rhino, dates from ES3 where it was proposed, prototyped, and shot down in Ecma TC39 TG1, but kept in the implementations. Again, this syntax helps discriminate on e's duck type or instanceof without requiring a hand-coded if-else chain or switch, with mandatory re-throw in final-else or default.

In TC39 we had a discussion, I think in March 2011, about generalized refutable match as proposed by dherman:

strawman:pattern_matching

This was considered not baked enough to put in ES6. The tension with destructuring is an ongoing issue in my view. Also, Dave's strawman changes catch from how it works in SpiderMonkey and Rhino, so a pattern implies an 'if'.

I think we need to talk about refutable patterns and matching again, before we beat the catch-if dead horse once again. Suggest new spin-off thread (different subject).

# Brendan Eich (6 years ago)

John J Barton wrote:

On Wed, Dec 19, 2012 at 8:11 AM, Brandon Benvie <brandon at brandonbenvie.com <mailto:brandon at brandonbenvie.com>> wrote:

The magical quality that throw has is its ability to end multiple
call frames at once. Much like a second continuation channel, or
the error channel in a promise, it escapes past any number of
listeners on the normal channel, only stopping at the first
listener on the error channel.

Well said: it's always possible to argue for 'goto' in specific cases. With experience we've learned that these seemingly sensible features have debilitating system effects.

Which sensible features do you mean? Termination-style exception handling, meaning 'throw'?

JS1 had no try/catch so too many fail-soft silence-is-deadly conditions. This is a big problem still.

ES3 added try/catch and it has been a mixed bag, but as Brandon points out, you can terminate multiple frames (dynamically linked -- no static confinement) with exceptions. This is important for one of two prevailing use-cases for try/catch:

  1. Local protocols where a producer needs to terminate an iteration without a-priori coordination with arbitrary consumers, including specifically without a magic OOB value meaning "stop".

  2. Long-distance try/catch near the event loop, to deal with some poorly understood but recoverable problem in subsystem (e.g., the DOM, XPCOM, COM or Windows8, etc. etc.)

The value of (2) is low but real.

StopIteration is only one example of (1).

The mistake of including StopIteration should not be used to justify including more mistakes.

This is Crockfordian in its dire sweep but I don't think you've made the case. What's your preferred alternative?

Communicating two different non-error results through the normal return channel is not easy,

How?

# John J Barton (6 years ago)

On Wed, Dec 19, 2012 at 11:23 AM, Brendan Eich <brendan at mozilla.com> wrote:

John J Barton wrote:

On Wed, Dec 19, 2012 at 8:11 AM, Brandon Benvie <

brandon at brandonbenvie.com <mailto:brandon at brandonbenvie.**com<brandon at brandonbenvie.com>>> wrote:

The magical quality that throw has is its ability to end multiple
call frames at once. Much like a second continuation channel, or
the error channel in a promise, it escapes past any number of
listeners on the normal channel, only stopping at the first
listener on the error channel.

Well said: it's always possible to argue for 'goto' in specific cases. With experience we've learned that these seemingly sensible features have debilitating system effects.

Which sensible features do you mean? Termination-style exception handling, meaning 'throw'?

goto, and similar control transfers. 'throw' has proven to be a useful exception ... because we use it for exceptions.

JS1 had no try/catch so too many fail-soft silence-is-deadly conditions. This is a big problem still.

ES3 added try/catch and it has been a mixed bag, but as Brandon points out, you can terminate multiple frames (dynamically linked -- no static confinement) with exceptions. This is important for one of two prevailing use-cases for try/catch:

  1. Local protocols where a producer needs to terminate an iteration without a-priori coordination with arbitrary consumers, including specifically without a magic OOB value meaning "stop".

  2. Long-distance try/catch near the event loop, to deal with some poorly understood but recoverable problem in subsystem (e.g., the DOM, XPCOM, COM or Windows8, etc. etc.)

The value of (2) is low but real.

I disagree. (2) is essential exactly because we depend on subsystems.

StopIteration is only one example of (1).

And one too many, exactly because (2) is so vital. We should not pollute the critical feature of "throw exceptions" with "throw because I can't figure out another implementation"

The mistake of including StopIteration should not be used to justify

including more mistakes.

This is Crockfordian in its dire sweep but I don't think you've made the case. What's your preferred alternative?

Don't include features that require StopIteration.

Communicating two different non-error results through the normal return

channel is not easy,

How?

Sorry, I should have said: finding a way to implement StopIteration without using the throw-exceptions channel may not be easy, but it does not seem impossible.

jjb

# Claude Pache (6 years ago)

Le 20 déc. 2012 à 00:31, John J Barton <johnjbarton at johnjbarton.com> a écrit :

On Wed, Dec 19, 2012 at 11:23 AM, Brendan Eich <brendan at mozilla.com> wrote:

John J Barton wrote:

On Wed, Dec 19, 2012 at 8:11 AM, Brandon Benvie <brandon at brandonbenvie.com <mailto:brandon at brandonbenvie.com>> wrote:

The magical quality that throw has is its ability to end multiple
call frames at once. Much like a second continuation channel, or
the error channel in a promise, it escapes past any number of
listeners on the normal channel, only stopping at the first
listener on the error channel.

Well said: it's always possible to argue for 'goto' in specific cases. With experience we've learned that these seemingly sensible features have debilitating system effects.

Which sensible features do you mean? Termination-style exception handling, meaning 'throw'?

goto, and similar control transfers. 'throw' has proven to be a useful exception ... because we use it for exceptions.

With goto, you need (1) to know where to go, and (2) to pick a label name and put it at two possibly distant places. With throw/catch, you don't; therefore I think that throw/catch is superior (where it is possible to replace goto by throw/catch, which I think is most of the time).

Throw/catch is useful for exceptions, it doesn't mean that such a mechanism could not have other legitimate uses. I think that we are not accustomed to use it for anything else than exceptions in everyday code, because we don't often need it and we generally find a workaround. StopIteration is IMHO a nice example of a good use of throwing a non-error: The iterator is asked for the next value, but there is none, so it throws (but it is not an error), and the execution resume where it should (e.g. after a for/of loop or at some place manually identified by a catch clause), without the need to add some branching statement at every place the iterator is invoked.

Claude

# John J Barton (6 years ago)

On Wed, Dec 19, 2012 at 4:39 PM, Claude Pache <claude.pache at gmail.com>wrote:

Throw/catch is useful for exceptions, it doesn't mean that such a mechanism could not have other legitimate uses. I think that we are not accustomed to use it for anything else than exceptions in everyday code, because we don't often need it and we generally find a workaround.

The issue is not lack of imagination. On the contrary, all other uses interfere with using throw/catch for exceptions.

Debuggers provide break-on-exception as a valuable development feature. Why? Because developers know that an exception is something the merits special attention. If we want to invest in throw/catch we should provide features like runtime detection of would-be-caught.

StopIteration is IMHO a nice example of a good use of throwing a non-error: The iterator is asked for the next value, but there is none, so it throws (but it is not an error), and the execution resume where it should (e.g. after a for/of loop or at some place manually identified by a catch clause), without the need to add some branching statement at every place the iterator is invoked.

I disagree. If this form of iteration is so important, implement it properly, not as a hack on throw/catch.

jjb

# Brendan Eich (6 years ago)

John J Barton wrote:

On Wed, Dec 19, 2012 at 11:23 AM, Brendan Eich <brendan at mozilla.com <mailto:brendan at mozilla.com>> wrote:

John J Barton wrote:

    On Wed, Dec 19, 2012 at 8:11 AM, Brandon Benvie
    <brandon at brandonbenvie.com <mailto:brandon at brandonbenvie.com>
    <mailto:brandon at brandonbenvie.com
    <mailto:brandon at brandonbenvie.com>>> wrote:

        The magical quality that throw has is its ability to end
    multiple
        call frames at once. Much like a second continuation
    channel, or
        the error channel in a promise, it escapes past any number of
        listeners on the normal channel, only stopping at the first
        listener on the error channel.


    Well said: it's always possible to argue for 'goto' in
    specific cases. With experience we've learned that these
    seemingly sensible features have debilitating system effects.


Which sensible features do you mean? Termination-style exception
handling, meaning 'throw'?

goto, and similar control transfers. 'throw' has proven to be a useful exception ... because we use it for exceptions.

Good, we agree (not sure what you meant by debilitating system effects, though -- not disagreeing, just unclear!).

JS1 had no try/catch so too many fail-soft silence-is-deadly
conditions. This is a big problem still.

ES3 added try/catch and it has been a mixed bag, but as Brandon
points out, you can terminate multiple frames (dynamically linked
-- no static confinement) with exceptions. This is important for
one of two prevailing use-cases for try/catch:

1. Local protocols where a producer needs to terminate an
iteration without a-priori coordination with arbitrary consumers,
including specifically without a magic OOB value meaning "stop".

2. Long-distance try/catch near the event loop, to deal with some
poorly understood but recoverable problem in subsystem (e.g., the
DOM, XPCOM, COM or Windows8, etc. etc.)

The value of (2) is low but real.

I disagree. (2) is essential exactly because we depend on subsystems.

Disagree on "low" or "real"? Evidently not "real", so must be "low". What I mean is using try/catch near the event loop to drop a "do not understand" exception on the floor instead of allowing it to terminate the loop (or do whatever an uncaught exception would do) is pretty low-value. Perhaps the event loop auto-restarts without a catch. Is the canonical console.log of the uncaught exception useful? Only if a developer is watching.

My "low" does not mean "zero" -- that would take away the "real" value I ascribed. But it's pretty silly to say that try/catch for (2) is highly useful, in the sense that it adds a lot of value. If event loops auto-respawn it's at best a convenience and logging opportunity.

StopIteration is only one example of (1).

And one too many, exactly because (2) is so vital. We should not pollute the critical feature of "throw exceptions" with "throw because I can't figure out another implementation"

The two use-cases are almost always disjoint. StopIteration is almost always auto-handled by for-of constructs.

    The mistake of including StopIteration should not be used to
    justify including more mistakes.


This is Crockfordian in its dire sweep but I don't think you've
made the case. What's your preferred alternative?

Don't include features that require StopIteration.

The alternatives are worse. We've been over this. If you don't have something new to propose, you're not going to move the needle here at all.

# Brendan Eich (6 years ago)

Claude Pache wrote:

The iterator is asked for the next value, but there is none, so it throws (but it is not an error)

Good point -- not all exceptions are errors, but all errors are exceptions (or should be -- ignore the errno-like nonsense in various legacy APIs!).

# Brendan Eich (6 years ago)

John J Barton wrote:

Debuggers provide break-on-exception as a valuable development feature. Why? Because developers know that an exception is something the merits special attention. If we want to invest in throw/catch we should provide features like runtime detection of would-be-caught.

You seem to be assuming debuggers are the tail that wags the dog, and exceptions are only errors that one must debug. Neither is true.

Debuggers must look inside of closures and get backstage-passes from the GC. They must bear many burdens for the good of the user. Any debugger worth using must be able to stop-on-only-these-exceptions, classifying by instance, instanceof/"class", duck-type or other criteria.

# John J Barton (6 years ago)

On Wed, Dec 19, 2012 at 7:55 PM, Brendan Eich <brendan at mozilla.com> wrote:

John J Barton wrote:

On Wed, Dec 19, 2012 at 11:23 AM, Brendan Eich <brendan at mozilla.com<mailto: brendan at mozilla.com>> wrote:

The value of (2) is low but real.

I disagree. (2) is essential exactly because we depend on subsystems.

Disagree on "low" or "real"? Evidently not "real", so must be "low". What I mean is using try/catch near the event loop to drop a "do not understand" exception on the floor instead of allowing it to terminate the loop (or do whatever an uncaught exception would do) is pretty low-value. Perhaps the event loop auto-restarts without a catch. Is the canonical console.log of the uncaught exception useful? Only if a developer is watching.

throw happens at any depth and trapping the throw in a development system is -- or should be -- one of the fundamental operations supporting development. An exception may arrive from outside of the developers control, but during development most exceptions are bugs. In a dynamic development environment we are mostly handling exceptions because our code far from our goal. In a dynamic system syntax errors, reference errors, and many kinds of algorithm errors surface as exceptions. Eventually we approach our goal and the normal code has no exceptions. Unless we have foolishly polluted our error handling mechanism with non-errors.

My "low" does not mean "zero" -- that would take away the "real" value I ascribed. But it's pretty silly to say that try/catch for (2) is highly useful, in the sense that it adds a lot of value. If event loops auto-respawn it's at best a convenience and logging opportunity.

That's a very pessimistic view. The primary goal for try/catch should be to guard our code from subsystem issues. That means the try/catch should be near the bottom of our stack, where we cross over. Placing try/catch at the top for logging just means the subsystems are unpredictable and our development solutions are so primitive we must resort to logging.

StopIteration is only one example of (1).

And one too many, exactly because (2) is so vital. We should not pollute the critical feature of "throw exceptions" with "throw because I can't figure out another implementation"

The two use-cases are almost always disjoint. StopIteration is almost always auto-handled by for-of constructs.

Nevertheless the StopIteration triggers the exception handling machinery as if it were an exception. The fact that it is handled by a catch is sadly opaque to this machinery.

     The mistake of including StopIteration should not be used to
    justify including more mistakes.


This is Crockfordian in its dire sweep but I don't think you've
made the case. What's your preferred alternative?

Don't include features that require StopIteration.

The alternatives are worse. We've been over this. If you don't have something new to propose, you're not going to move the needle here at all.

I'm only trying to prevent the needle from moving further, as proposed by Claude.

I don't have any interest in StopIteration, but it seems pretty obvious that an alternative could be created: dry { mayDhrowStopIteration(); } datch(iStopped) { geeImDone(); } That is, the entire try/catch/throw machinery could be copied and wired into new syntax for the StopIteration case. The dry/datch/dhrow would be independent of try/catch/throw.

Such a solution make the cost of StopIteration much higher, as it should be. By hi-jacking the exception machinery, the cost of StopIteration is artificially low. That is what we mean by a hack: a way of accomplishing a goal that shifts costs on to others in the future.

jjb

# John J Barton (6 years ago)

On Wed, Dec 19, 2012 at 8:01 PM, Brendan Eich <brendan at mozilla.com> wrote:

John J Barton wrote:

Debuggers provide break-on-exception as a valuable development feature. Why? Because developers know that an exception is something the merits special attention. If we want to invest in throw/catch we should provide features like runtime detection of would-be-caught.

You seem to be assuming debuggers are the tail that wags the dog, and exceptions are only errors that one must debug. Neither is true.

Rather than asking you to guess my assumptions, I'll tell you straight out that TC39 should pay more attention to debugging. Rather than viewing debugging as an optional wagging appendage, we should consider debugging as one of the essential elements in success of language features. (And proposing that I think exceptions are the only errors one must debug is just silly ;-).

Debuggers must look inside of closures and get backstage-passes from the GC. They must bear many burdens for the good of the user. Any debugger worth using must be able to stop-on-only-these-**exceptions, classifying by instance, instanceof/"class", duck-type or other criteria.

Claude's proposal leads to a small extra burden on debuggers but a much larger and broader burden on developers. It requires developers to build rule sets for exceptions-that-are-not-really-exceptions and to re-enter and maintain these rule sets across many projects and environments. All to save the fans of StopIteration style control flow from doing the right thing in the first place.

jjb

# Brendan Eich (6 years ago)

John J Barton wrote:

Unless we have foolishly polluted our error handling mechanism with non-errors.

Exception-handling > error-handling. Perhaps we disagree, but it's not

called "error-handling" -- it is called "exception handling" for good reason. Exceptional conditions are not all errors.

# Herby Vojčík (6 years ago)

Brendan Eich wrote:

John J Barton wrote:

Unless we have foolishly polluted our error handling mechanism with non-errors.

Exception-handling > error-handling. Perhaps we disagree, but it's not called "error-handling" -- it is called "exception handling" for good reason. Exceptional conditions are not all errors.

But polluting single physical channel with all the orthogonal logical channels is at least questionable, isn't it? Is the idea 9f multiple channels (as I posted a few mails ago) not a possibility>

# Brendan Eich (6 years ago)

John J Barton wrote:

I'll tell you straight out that TC39 should pay more attention to debugging.

How would that work? Debuggers are evolving rapidly, should we standardize one now? TC39 has a good cohort of JS developers who use debuggers in their real jobs. What should we be doing for debuggers per se that we are not?

Rather than viewing debugging as an optional wagging appendage,

I didn't write "optional", and dogs' tails are there for good reason! :-P

A language's design may include such things as invariants (e.g. closure variable non-enumerability) that debuggers break. Debuggers break abstractions. This does not mean that languages should provide unprivileged APIs for self-hosting debuggers. That would be a security disaster on the web.

To get back to the specific problem of exceptions: they do get thrown sometimes, and I've had to debug problems where I wanted only one particular throw (from an XPCOM error return code, as it happens, a real pain to track down without debugger support).

In C++ this requires great GDB pain. In JS, it's a lot easier with the VM support for filtering based on exception type. We're working on such VM support in SpiderMonkey, see developer.mozilla.org/en-US/docs/SpiderMonkey/JS_Debugger_API_Reference/Debugger#onExceptionUnwind().

we should consider debugging as one of the essential elements in success of language features. (And proposing that I think exceptions are the only errors one must debug is just silly ;-).

You keep writing "error-handling" when the topic is exception-handling, though. Why is that?

Debuggers must look inside of closures and get backstage-passes
from the GC. They must bear many burdens for the good of the user.
Any debugger worth using must be able to
stop-on-only-*these*-exceptions, classifying by instance,
instanceof/"class", duck-type or other criteria.

Claude's proposal leads to a small extra burden on debuggers but a much larger and broader burden on developers. It requires developers to build rule sets for exceptions-that-are-not-really-exceptions and to re-enter and maintain these rule sets across many projects and environments.

If you mean by "Claude's proposal" the catch (e if ...) syntax already in SpiderMonkey and Rhino, then I don't follow. The burden for filtering exceptions exists whether one has only catch (e) or catch (e if ...) syntax. With only catch (e), one must hand-code an if-else chain or switch, and worry about re-throwing in the default/final-else case.

So how is any new burden imposed by Claude's proposal (catch (e if ...))? It either exists in the structure of the code using exceptions, or it doesn't.

What syntax one must use to deal with the burden does not affect the burden's existence or magnitude -- although I contend that having only catch (e) makes missing re-throw bugs likelier.

All to save the fans of StopIteration style control flow from doing the right thing in the first place.

What "right thing" is that?

Your aggrieved and kind of snarky posts may make you feel good, but if you don't have a serious alternative, and if you insist there are no other non-error uses of exceptions, then we'll have to part ways on this issue.

# Brendan Eich (6 years ago)

Herby Vojčík wrote:

Brendan Eich wrote:

John J Barton wrote:

Unless we have foolishly polluted our error handling mechanism with non-errors.

Exception-handling > error-handling. Perhaps we disagree, but it's not called "error-handling" -- it is called "exception handling" for good reason. Exceptional conditions are not all errors.

But polluting single physical channel with all the orthogonal logical channels is at least questionable, isn't it?

Adding exception channels at least avoids adding another value type/singleton. But I don't see how it works. More below.

Is the idea of multiple channels (as I posted a few mails ago) not a possibility>

I doubt it will gain champions. Once you have try/catch/finally, you've got enough to build such things via libraries. Adding channels under the hood doesn't help hide StopIteration, since control flow must stop and unwind when it is thrown. We can't blast past default-channel try/catch/finally's seeking one that handles StopIteration, we must at least run the finally clauses.

But those finally clauses if written for ES3 or above will assume that any abrupt completion was a default-channel exception, i.e, that the catch clause ran. Your proposal as I understand it breaks that compatibility constraint.

# Herby Vojčík (6 years ago)

Brendan Eich wrote:

Herby Vojčík wrote:

Is the idea of multiple channels (as I posted a few mails ago) not a possibility>

I doubt it will gain champions. Once you have try/catch/finally, you've got enough to build such things via libraries. Adding channels under the hood doesn't help hide StopIteration, since control flow must stop and unwind when it is thrown. We can't blast past default-channel try/catch/finally's seeking one that handles StopIteration, we must at least run the finally clauses.

Yes, that was how I meant it. And every channel's finallies, not just the default one.

But those finally clauses if written for ES3 or above will assume that any abrupt completion was a default-channel exception, i.e, that the catch clause ran. Your proposal as I understand it breaks that compatibility constraint.

Hm. Good point, did not think of this.

# John J Barton (6 years ago)

On Wed, Dec 19, 2012 at 11:43 PM, Brendan Eich <brendan at mozilla.com> wrote:

John J Barton wrote:

I'll tell you straight out that TC39 should pay more attention to debugging.

How would that work? Debuggers are evolving rapidly, should we standardize one now? TC39 has a good cohort of JS developers who use debuggers in their real jobs. What should we be doing for debuggers per se that we are not?

TC39 invests and encourages amazing and thorough discussions on compiler-oriented ergonomics of ECMAScript yet the total programming experience includes other issues, especially debugging. Explicitly consider and encourage examination of the debugging implications of language design to improve the total development experience.

I'll give a specific example below. Obviously not all language features have significant debugger experience issues. But module loading, promises, generators, pragmas, observe, proxies are all things impact on development should be considered.

Rather than viewing debugging as an optional wagging appendage,

I didn't write "optional", and dogs' tails are there for good reason! :-P

A language's design may include such things as invariants (e.g. closure variable non-enumerability) that debuggers break. Debuggers break abstractions. This does not mean that languages should provide unprivileged APIs for self-hosting debuggers. That would be a security disaster on the web.

How might this point be related to the topic under discussion?

To get back to the specific problem of exceptions: they do get thrown sometimes, and I've had to debug problems where I wanted only one particular throw (from an XPCOM error return code, as it happens, a real pain to track down without debugger support).

In C++ this requires great GDB pain. In JS, it's a lot easier with the VM support for filtering based on exception type. We're working on such VM support in SpiderMonkey, see developer.mozilla.org/** en-US/docs/SpiderMonkey/JS_Debugger_API_Reference/ Debugger#onExceptionUnwind()developer.mozilla.org/en-US/docs/SpiderMonkey/JS_Debugger_API_Reference/Debugger#onExceptionUnwind() .

I'm excited to see this kind of advance. However, as I said earlier, this is the smaller part of the impact of non-error exception handling. In addition to such APIs as you cite, the specification that separates error and non-error exceptions must also be considered. Depending on the design, this could be anywhere from "only errors raise exceptions" to "developers must supply a algorithm to decide". Languages with a centrally controlled type system (I have in mind Java) provide a relatively simple way to separate these exceptions.

we should consider debugging as one of the essential elements in success

of language features. (And proposing that I think exceptions are the only errors one must debug is just silly ;-).

You keep writing "error-handling" when the topic is exception-handling, though. Why is that?

If some specific statement I made is confusing I'll try to clarify.

 Debuggers must look inside of closures and get backstage-passes
from the GC. They must bear many burdens for the good of the user.
Any debugger worth using must be able to
stop-on-only-*these*-**exceptions, classifying by instance,
instanceof/"class", duck-type or other criteria.

Claude's proposal leads to a small extra burden on debuggers but a much larger and broader burden on developers. It requires developers to build rule sets for exceptions-that-are-not-**really-exceptions and to re-enter and maintain these rule sets across many projects and environments.

If you mean by "Claude's proposal" the catch (e if ...) syntax already in SpiderMonkey and Rhino, then I don't follow. The burden for filtering exceptions exists whether one has only catch (e) or catch (e if ...) syntax. With only catch (e), one must hand-code an if-else chain or switch, and worry about re-throwing in the default/final-else case.

So how is any new burden imposed by Claude's proposal (catch (e if ...))? It either exists in the structure of the code using exceptions, or it doesn't.

Claude's proposal says: "Rationale: Although try/catch mechanism was initially intended for treating errors, it could be used in normal control flow with non-error condition. ES.next sanction this pattern with StopIteration. "

That is the specific statement I wish to challenge.

What syntax one must use to deal with the burden does not affect the burden's existence or magnitude -- although I contend that having only catch (e) makes missing re-throw bugs likelier.

All to save the fans of StopIteration style control flow from doing the

right thing in the first place.

What "right thing" is that?

Your aggrieved and kind of snarky posts may make you feel good, but if you don't have a serious alternative, and if you insist there are no other non-error uses of exceptions, then we'll have to part ways on this issue.

As I have said before, StopIteration could have been specified with its own control-flow mechanism rather than try/catch/throw. Perhaps it is well known that StopIteration-like uses of try/catch/throw can be cleanly separated from error cases without developer intervention?

I'm sorry if my frustration with the crude development tools we have for the Web colors the tone of my posts. They do not make me "feel good"; they just amplify my sense that ES is getting much more complex but we don't have the resources to deal with the consequences in the tools end.

jjb

# Brendan Eich (6 years ago)

John J Barton wrote:

On Wed, Dec 19, 2012 at 11:43 PM, Brendan Eich <brendan at mozilla.com <mailto:brendan at mozilla.com>> wrote:

John J Barton wrote:

    I'll tell you straight out that TC39 should pay more attention
    to debugging.


How would that work? Debuggers are evolving rapidly, should we
standardize one now? TC39 has a good cohort of JS developers who
use debuggers in their real jobs. What should we be doing for
debuggers _per se_ that we are not?

TC39 invests and encourages amazing and thorough discussions on compiler-oriented ergonomics of ECMAScript yet the total programming experience includes other issues, especially debugging. Explicitly consider and encourage examination of the debugging implications of language design to improve the total development experience.

We do try. You know AWB has tons of experience here from Smalltalk. MarkM, Doug, Alex, Yehuda, Arv, all bring to bear considerable experience.

I'll give a specific example below.

Great, thanks.

Obviously not all language features have significant debugger experience issues. But module loading, promises, generators, pragmas, observe, proxies are all things impact on development should be considered.

I'm telling you they have been for those things (especially for pragmas, which we deferred). Let's get to specifics, or this could go on and on :-|.

    Rather than viewing debugging as an optional wagging appendage,


I didn't write "optional", and dogs' tails are there for good
reason! :-P

A language's design may include such things as invariants (e.g.
closure variable non-enumerability) that debuggers break.
Debuggers break abstractions. This does not mean that languages
should provide unprivileged APIs for self-hosting debuggers. That
would be a security disaster on the web.

How might this point be related to the topic under discussion?

Tail = debugging closures including enumerating their environment variables. Dog = JS with closures in unprivileged dominant use-case, no such debugging APIs.

To get back to the specific problem of exceptions: they do get
thrown sometimes, and I've had to debug problems where I wanted
only one particular throw (from an XPCOM error return code, as it
happens, a real pain to track down without debugger support).

In C++ this requires great GDB pain. In JS, it's a lot easier with
the VM support for filtering based on exception type. We're
working on such VM support in SpiderMonkey, see
https://developer.mozilla.org/en-US/docs/SpiderMonkey/JS_Debugger_API_Reference/Debugger#onExceptionUnwind()
<https://developer.mozilla.org/en-US/docs/SpiderMonkey/JS_Debugger_API_Reference/Debugger#onExceptionUnwind%28%29>.

I'm excited to see this kind of advance. However, as I said earlier, this is the smaller part of the impact of non-error exception handling. In addition to such APIs as you cite, the specification that separates error and non-error exceptions must also be considered.

TC39 is not and will not make any such "global" a-priori specification.

People expect to subclass Error, the spec already does. That's fair. But you can throw any value, and real code does use this. Narcissus in the original metacircular form had very pretty exception-but-not-error throwing to implement throw, break and continue (including to label), and return:

BrendanEich/narcissus/blob/master/lib/jsexec.js#L476, BrendanEich/narcissus/blob/master/lib/jsexec.js#L484, BrendanEich/narcissus/blob/master/lib/jsexec.js#L512, BrendanEich/narcissus/blob/master/lib/jsexec.js#L517

Depending on the design, this could be anywhere from "only errors raise exceptions" to "developers must supply a algorithm to decide". Languages with a centrally controlled type system (I have in mind Java) provide a relatively simple way to separate these exceptions.

And how is this relevant? I'm not snarking back. JS != Java.

    we should consider debugging as one of the essential elements
    in success of language features. (And proposing that I think
    exceptions are the only errors one must debug is just silly ;-).


You keep writing "error-handling" when the topic is
exception-handling, though. Why is that?

If some specific statement I made is confusing I'll try to clarify.

Let's try to agree that exceptions as a set subsumes errors (ignoring bad old errno-ish patterns in legacy APIs).

If you mean by "Claude's proposal" the catch (e if ...) syntax
already in SpiderMonkey and Rhino, then I don't follow. The burden
for filtering exceptions exists whether one has only catch (e) or
catch (e if ...) syntax. With only catch (e), one must hand-code
an if-else chain or switch, and worry about re-throwing in the
default/final-else case.

So how is any new burden imposed by Claude's proposal (catch (e if
...))? It either exists in the structure of the code using
exceptions, or it doesn't.

Claude's proposal says: "Rationale: Although try/catch mechanism was initially intended for treating errors, it could be used in normal control flow with non-error condition. ES.next sanction this pattern with StopIteration. "

That is the specific statement I wish to challenge.

Claude's "it could be used in normal control flow" was too subjunctive, and as I wrote in an earlier reply, because such non-error exceptions are used in the field, and have been since ES3, StopIteration is a red herring, or at best one of large-N and a future one at that.

What syntax one must use to deal with the burden does not affect
the burden's existence or magnitude -- although I contend that
having only catch (e) makes missing re-throw bugs likelier.


    All to save the fans of StopIteration style control flow from
    doing the right thing in the first place.

What "right thing" is that?

Your aggrieved and kind of snarky posts may make you feel good,
but if you don't have a serious alternative, and if you insist
there are no other non-error uses of exceptions, then we'll have
to part ways on this issue.

As I have said before, StopIteration could have been specified with its own control-flow mechanism rather than try/catch/throw. Perhaps it is well known that StopIteration-like uses of try/catch/throw can be cleanly separated from error cases without developer intervention?

By what means? You have not specified. Please, no dry/datch/dinally jokes.

I'm sorry if my frustration with the crude development tools we have for the Web colors the tone of my posts. They do not make me "feel good"; they just amplify my sense that ES is getting much more complex but we don't have the resources to deal with the consequences in the tools end.

The SpiderMonkey Debugger API is already dealing with extensions we've carried for years, e.g. generators. Please look into it before iterating frustation :-).

# John J Barton (6 years ago)

On Thu, Dec 20, 2012 at 11:20 AM, Brendan Eich <brendan at mozilla.com> wrote:

John J Barton wrote:

On Wed, Dec 19, 2012 at 11:43 PM, Brendan Eich <brendan at mozilla.com<mailto:

brendan at mozilla.com>> wrote:

In JS, it's a lot easier with

the VM support for filtering based on exception type. We're
working on such VM support in SpiderMonkey, see
https://developer.mozilla.org/**en-US/docs/SpiderMonkey/JS_**

Debugger_API_Reference/**Debugger#onExceptionUnwind()developer.mozilla.org/en-US/docs/SpiderMonkey/JS_Debugger_API_Reference/Debugger#onExceptionUnwind() <developer.mozilla.org/en-US/docs/SpiderMonkey/ JS_Debugger_API_Reference/**Debugger#onExceptionUnwind%28%**29developer.mozilla.org/en-US/docs/SpiderMonkey/JS_Debugger_API_Reference/Debugger#onExceptionUnwind()

.

I'm excited to see this kind of advance. However, as I said earlier, this is the smaller part of the impact of non-error exception handling. In addition to such APIs as you cite, the specification that separates error and non-error exceptions must also be considered.

TC39 is not and will not make any such "global" a-priori specification.

People expect to subclass Error, the spec already does. That's fair. But you can throw any value, and real code does use this. Narcissus in the original metacircular form had very pretty exception-but-not-error throwing to implement throw, break and continue (including to label), and return:

BrendanEich/narcissus/blob/ master/lib/jsexec.js#L476BrendanEich/narcissus/blob/master/lib/jsexec.js#L476, BrendanEich/narcissus/blob/ master/lib/jsexec.js#L484BrendanEich/narcissus/blob/master/lib/jsexec.js#L484, BrendanEich/narcissus/blob/ master/lib/jsexec.js#L512BrendanEich/narcissus/blob/master/lib/jsexec.js#L512, BrendanEich/narcissus/blob/ master/lib/jsexec.js#L517BrendanEich/narcissus/blob/master/lib/jsexec.js#L517

Depending on the design, this could be anywhere from "only errors raise

exceptions" to "developers must supply a algorithm to decide". Languages with a centrally controlled type system (I have in mind Java) provide a relatively simple way to separate these exceptions.

And how is this relevant? I'm not snarking back. JS != Java.

Java is one example of a language that supports non-error uses of the try/catch exception mechanism. Part of that support includes a way for debuggers to distinguish errors uses from non-error uses. Encouraging additional non-error use of the JavaScript try/catch mechanism without a similar means to separate them from error uses will make features like onExceptionUnwind tedious for developers to use.

jjb

# Brendan Eich (6 years ago)

John J Barton wrote:

    Depending on the design, this could be anywhere from "only
    errors raise exceptions" to "developers must supply a
    algorithm to decide". Languages with a centrally controlled
    type system (I have in mind Java) provide a relatively simple
    way to separate these exceptions.


And how is this relevant? I'm not snarking back. JS != Java.

Java is one example of a language that supports non-error uses of the try/catch exception mechanism. Part of that support includes a way for debuggers to distinguish errors uses from non-error uses. Encouraging additional non-error use

Again, I object. StopIteration is not "encouraging additional non-error [uses of try/catch]" outside of specialized, written-by-experts libraries such as taskjs.org.

The exceptions-are-not-all-errors cat is out of the bag. You don't seem to agree but you haven't rebutted directly. I cry foul.

of the JavaScript try/catch mechanism without a similar means to separate them from error uses

Again, without a type system, how?

Testing catch (e if e instanceof Error) was an explicit intended use of catch guards from the ES3 days. With standard catch you would write an if-else chain and remember to re-throw in final else. This is quite doable now, so what's the problem? Note that DOMException instanceof Error per www.w3.org/TR/WebIDL/#es-exceptions.

Yes, instanceof does not work cross-frame. This has been debated on es-discuss a lot. For same-realm uses, it suffices, as people here have pointed out recently. Exception catching may favor same-realm, I'm not sure. But this is a separate issue.

will make features like onExceptionUnwind tedious for developers to use.

This is just the lowest tier of the API and we're not done yet.

To be frank, I think your frustration is perfectly understandable, but not grounds for general exhortations or judgments against particulars (StopIteration) that are not relevant (for-of handles outside of specialized taskjs settings), or at the very least not decisive in light of precedent (instanceof Error testing). Anyway, I hope to have shed some light here. How'd I do?

# John J Barton (6 years ago)

On Thu, Dec 20, 2012 at 12:38 PM, Brendan Eich <brendan at mozilla.com> wrote:

John J Barton wrote:

    Depending on the design, this could be anywhere from "only
    errors raise exceptions" to "developers must supply a
    algorithm to decide". Languages with a centrally controlled
    type system (I have in mind Java) provide a relatively simple
    way to separate these exceptions.


And how is this relevant? I'm not snarking back. JS != Java.

Java is one example of a language that supports non-error uses of the try/catch exception mechanism. Part of that support includes a way for debuggers to distinguish errors uses from non-error uses. Encouraging additional non-error use

Again, I object. StopIteration is not "encouraging additional non-error [uses of try/catch]" outside of specialized, written-by-experts libraries such as taskjs.org.

The exceptions-are-not-all-errors cat is out of the bag. You don't seem to agree but you haven't rebutted directly. I cry foul.

But I do agree! It's Claude that proposes to release the cat. It's Claude proposal we are discussing, not StopIteration, you've already declared it out of bounds.

of the JavaScript try/catch mechanism without a similar means to separate

them from error uses

Again, without a type system, how?

Hmm: maybe some as trivial as a property 'isNotException'. Mandated on StopIteration, allowed on user objects.

Testing catch (e if e instanceof Error) was an explicit intended use of catch guards from the ES3 days. With standard catch you would write an if-else chain and remember to re-throw in final else. This is quite doable now, so what's the problem?

I will try again to explain the problem. When throw x; is executed the debugger can gain control and alert the developer of the throw. If the throw is an error condition the developer did not expect, the alert guides them to improve the code. However, if the debugger alerts often for conditions that are not important, the developer will turn off the alert feature. The result is a poorer tool. Thus we seek near zero false positive alerts. This much I believe you understand.

Testing catch (e if e instanceof Error) is fine for developers but the similar test in the debugger a list of rules like "e instanceof Error". Unless the rules are standard, they will need to be entered and maintained by developers.

So yes this is 'doable' but it creates a large cost on the alert feature. Debuggers can each invent an ad hoc list of rules but if the fail or even differ across debuggers, the feature will fail to alert or alert too often, effectively preventing developers from using the feature. I hope this is clearer.

Note that DOMException instanceof Error per www.w3.org/TR/WebIDL/#* *es-exceptions www.w3.org/TR/WebIDL/#es-exceptions.

Yes, instanceof does not work cross-frame. This has been debated on es-discuss a lot. For same-realm uses, it suffices, as people here have pointed out recently. Exception catching may favor same-realm, I'm not sure. But this is a separate issue.

will make features like onExceptionUnwind tedious for developers to use.

This is just the lowest tier of the API and we're not done yet.

To be frank, I think your frustration is perfectly understandable, but not grounds for general exhortations or judgments against particulars (StopIteration) that are not relevant (for-of handles outside of specialized taskjs settings), or at the very least not decisive in light of precedent (instanceof Error testing). Anyway, I hope to have shed some light here. How'd I do?

Happy Holidays! jjb

# Brendan Eich (6 years ago)

John J Barton wrote:

On Thu, Dec 20, 2012 at 12:38 PM, Brendan Eich <brendan at mozilla.com <mailto:brendan at mozilla.com>> wrote:

John J Barton wrote:

    Java is one example of a language that supports non-error uses
    of the try/catch exception mechanism. Part of that support
    includes a way for debuggers to distinguish errors uses from
    non-error uses. Encouraging additional non-error use


Again, I object. StopIteration is not "encouraging additional
non-error [uses of try/catch]" outside of specialized,
written-by-experts libraries such as http://taskjs.org/.

The exceptions-are-not-all-errors cat is out of the bag. You don't
seem to agree but you haven't rebutted directly. I cry foul.

But I do agree! It's Claude that proposes to release the cat. It's Claude proposal we are discussing, not StopIteration, you've already declared it out of bounds.

I will avoid taking the StopIteration bait liberally sprinkled amidst the discussion :-P.

I would not say anything is "out of bounds", but StopIteration is just an example of non-error exceptions. It may stand out to some (we've shipped it since 2006 without a lot of pain on the debugger side -- or any, from my view of bugzilla [let me know if I missed a bug]) but the general ability to throw any value for dynamic control effects has been around since 1999, and it does see some use in the field.

So perhaps I'm just fussing over a point of order, but these fine points seem important to strive to agree on, or disagreement will spring up again based on different assumptions.

    of the JavaScript try/catch mechanism without a similar means
    to separate them from error uses


Again, without a type system, how?

Hmm: maybe some as trivial as a property 'isNotException'. Mandated on StopIteration, allowed on user objects.

Don't you mean isNotError or isNotErrorException?

Would you put it on Object.prototype?

It seems to me the (e instanceof Error) test is better, but there could be a duck-typing convenience. Perhaps "isErrorException" would be best, so you don't need to ensure it exists -- then the default undefined value converts to false. Perhaps there's a better name. We should focus on this if it's what you seek.

# John J Barton (6 years ago)

On Thu, Dec 20, 2012 at 2:16 PM, Brendan Eich <brendan at mozilla.com> wrote:

John J Barton wrote:

On Thu, Dec 20, 2012 at 12:38 PM, Brendan Eich <brendan at mozilla.com<mailto: brendan at mozilla.com>> wrote:

John J Barton wrote:

    Java is one example of a language that supports non-error uses
    of the try/catch exception mechanism. Part of that support
    includes a way for debuggers to distinguish errors uses from
    non-error uses. Encouraging additional non-error use


Again, I object. StopIteration is not "encouraging additional
non-error [uses of try/catch]" outside of specialized,
written-by-experts libraries such as http://taskjs.org/.

The exceptions-are-not-all-errors cat is out of the bag. You don't
seem to agree but you haven't rebutted directly. I cry foul.

But I do agree! It's Claude that proposes to release the cat. It's Claude proposal we are discussing, not StopIteration, you've already declared it out of bounds.

I will avoid taking the StopIteration bait liberally sprinkled amidst the discussion :-P.

I would not say anything is "out of bounds", but StopIteration is just an example of non-error exceptions. It may stand out to some (we've shipped it since 2006 without a lot of pain on the debugger side -- or any, from my view of bugzilla [let me know if I missed a bug]) but the general ability to throw any value for dynamic control effects has been around since 1999, and it does see some use in the field.

So perhaps I'm just fussing over a point of order, but these fine points seem important to strive to agree on, or disagreement will spring up again based on different assumptions.

Sorry I misread you. Your point is that Claude need make no proposal because it's a done deal. I believe ES explicit adoption of this approach could dramatically increase its use.

    of the JavaScript try/catch mechanism without a similar means
    to separate them from error uses


Again, without a type system, how?

Hmm: maybe some as trivial as a property 'isNotException'. Mandated on StopIteration, allowed on user objects.

Don't you mean isNotError or isNotErrorException?

Would you put it on Object.prototype?

It seems to me the (e instanceof Error) test is better, but there could be a duck-typing convenience. Perhaps "isErrorException" would be best, so you don't need to ensure it exists -- then the default undefined value converts to false. Perhaps there's a better name. We should focus on this if it's what you seek.

A lot of real code throws strings, for example from WebInspector:

throw "invalid color format";

Thus I suggest assuming that thrown objects are ErrorExceptions unless the standard (eg StopIterator) or developer marks them isNotErrorException. This path would also allow runtimes to optimize throwing such objects, perhaps avoiding some overhead required for exception handling.

jjb

# David Herman (6 years ago)

On Dec 20, 2012, at 2:16 PM, Brendan Eich <brendan at mozilla.com> wrote:

It seems to me the (e instanceof Error) test is better.

Yep. I see a lot of hand-wringing here over something that's AFAICT already solved.

# David Herman (6 years ago)

On Dec 20, 2012, at 2:47 PM, John J Barton <johnjbarton at johnjbarton.com> wrote:

A lot of real code throws strings, for example from WebInspector: throw "invalid color format"; Thus I suggest assuming that thrown objects are ErrorExceptions unless the standard (eg StopIterator) or developer marks them isNotErrorException.

This kind of fuzzy heuristic doesn't belong in a stdlib.