Closed domenic closed 8 years ago
throw.cancel
sounds grammatically viable but it feels strange - much stranger than things like new.target which are strange on their own.
Other alternatives can include an operator - something like throw@ e but that's likely worse.
In discussing the STC proposal, we came up with the idea of return.tail. This was rejected by some on the grounds that the special dot-keywords should be exclusively value-producing expressions (ie. identifier-like).
Here is what I have come up with as potential alternatives:
throw.cancel
throw/cancel
throw*
throw* cancel
return*
throw break
throw continue
continue [NoLineTerminatorHere] throw
throw return
{break, continue, return} are nice control-flow keywords, but already have meaning. I'm not sure adding "throw" before/after them is enough to avoid confusion with their existing meanings, all of which stop at loop or function boundaries.
throw*
by itself seems a bit dangerous, especially if you pair it with catch*
. It moves away from the semantic being "cancelation" and more toward it being "throw something special" with a non-obvious part of that specialness being that it doesn't cause HostReportErrors.
One problem with things like throw* cancel
is that I am unsure whether its counterpart is catch* cancel (e) { ... }
or catch cancel (e) { ... }
.
I am also vaguely interested in throw return
and return*
, in the spirit of "nonlocal return". I think the counterparts are catch return (e) { ... }
and catch return* (e) { ... }
. However, these have the possibility of shifting the entire language to "return", e.g. "return tokens", Promise.return(v)
, etc., which is kind of unfortunate. We could try to say that the concept is cancelation and the syntax just happens to use the word return. Maybe that is OK since we already have the mismatch of Promise.reject(r)
+ promise.catch(...)
.
For now I will tentatively proceed with:
throw return r
catch return (r) { ... }
generator.throwReturn(r)
Promise.cancel(r)
promise.catchReturn(r => { ... })
But this subject is definitely not closed...
Looks a little bit confusing, how about:
cancel&throw new CancellationReason('Yo!');
Ehhhhhh meh. Also BTW the CancelReason class was shot down by TC39; we should just use strings.
Anyway, it's introduces ambiguity:
foo&bar&cancel&throw new CancellationReason('Yo!');
Also BTW the CancelReason class was shot down by TC39; we should just use strings.
I think this is problematic - strings are value types and as such properties can't be attached to them. This means no .stack
and no ability to know where the cancellation originated which might be useful when debugging.
You can use objects if you want; it's not syntactically enforced or anything. But it was definitely a point of agreement that stacks should not be collected, as this is not an exceptional situation and the overhead of stack-tracking is not something we want to incur. That was one of the primary arguments in favor of a separate third state, instead of a special exception type.
@domenic I think the strong case for a separate third state is that it makes a lot of sense conceptually since you're not signalling completion or an error condition but actually something else.
I'm in complete agreement that we need cancellation semantics for async functions. and other things to come. I don't understand why stack traces wouldn't be useful - they wouldn't be as useful but if my code cancelled something and my app is stuck I sure probably want to know why. There is a whole class of tooling problems we're not even aware of yet.
I'll split it off into another issue.
Anyway, it's introduces ambiguity:
I don't believe that's the case, as throw
can only be used in statement position, not expression position.
cancel catch
and cancel throw
(with [NoLineTerminatorHere]) works, and so I've updated the current draft to have that.
throw cancel (foo)
already has a meaning, equivalent toconst x = cancel(foo); throw x;
. New syntax is needed.I don't have any ideas I currently love, but some committee members have suggested
throw.cancel
, which might be a fallback.I'd like to discourage idle suggestions from people who do not have experience in validating JavaScript grammar productions against the spec and against implementation constraints. Just throwing out your idea of what would be nice syntax is not a productive way to work in this repo.