ECMAScript throw
expressions
This proposal defines new syntax to throw exceptions from within an expression context.
Status
Stage: 2
Champion: Ron Buckton (@rbuckton)
For more information see the TC39 proposal process.
Authors
- Ron Buckton (@rbuckton)
Proposal
A throw
expression allows you to throw exceptions in expression contexts. For example:
- Parameter initializers
function save(filename = throw new TypeError("Argument required")) { }
- Arrow function bodies
lint(ast, { with: () => throw new Error("avoid using 'with' statements.") });
- Conditional expressions
function getEncoder(encoding) { const encoder = encoding === "utf8" ? new UTF8Encoder() : encoding === "utf16le" ? new UTF16Encoder(false) : encoding === "utf16be" ? new UTF16Encoder(true) : throw new Error("Unsupported encoding"); }
- Logical operations
class Product { get id() { return this._id; } set id(value) { this._id = value || throw new Error("Invalid value"); } }
A throw
expression does not replace a throw
statement due to the difference
in the precedence of their values. To maintain the precedence of the throw
statement,
we must add a lookahead restriction to ExpressionStatement
to avoid ambiguity.
Grammar
UnaryExpression[Yield, Await]:
`throw` UnaryExpression[?Yield, ?Await]
ExpressionStatement[Yield, Await]:
[lookahead ∉ {`{`, `function`, `async` [no |LineTerminator| here] `function`, `class`, `let [`, `throw`}] Expression[+In, ?Yield, ?Await] `;`
Other Notes
A throw
expression can be approximated in ECMAScript using something like the following definition:
const __throw = err => { throw err; };
// via helper...
function getEncoder1(encoding) {
const encoder = encoding === "utf8" ? new UTF8Encoder()
: encoding === "utf16le" ? new UTF16Encoder(false)
: encoding === "utf16be" ? new UTF16Encoder(true)
: __throw(new Error("Unsupported encoding"));
}
// via arrow...
function getEncoder2(encoding) {
const encoder = encoding === "utf8" ? new UTF8Encoder()
: encoding === "utf16le" ? new UTF16Encoder(false)
: encoding === "utf16be" ? new UTF16Encoder(true)
: (() => { throw new Error("Unsupported encoding"); })();
}
However, this has several downsides compared to a native implementation:
- The
__throw
helper will appear inerr.stack
in a host environment.- This can be mitigated in some hosts that have
Error.captureStackTrace
- This can be mitigated in some hosts that have
- Hosts require more information for optimization/deoptimization decisions as the
throw
is not local to the function. - Not ergonomic for debugging as the frame where the exception is raised is inside of the helper.
- Inline invoked arrow not ergonomic (at least 10 more symbols compared to native).
Resources
TODO
The following is a high-level list of tasks to progress through each stage of the TC39 proposal process:
Stage 1 Entrance Criteria
- Identified a "champion" who will advance the addition.
- Prose outlining the problem or need and the general shape of a solution.
- Illustrative examples of usage.
-
High-level API(proposal does not introduce an API).
Stage 2 Entrance Criteria
- Initial specification text.
- Optional. Transpiler support.
Stage 3 Entrance Criteria
- Complete specification text.
- Designated reviewers have signed off on the current spec text.
- The ECMAScript editor has signed off on the current spec text.
Stage 4 Entrance Criteria
- Test262 acceptance tests have been written for mainline usage scenarios and merged.
- Two compatible implementations which pass the acceptance tests: [1], [2].
- A pull request has been sent to tc39/ecma262 with the integrated spec text.
- The ECMAScript editor has signed off on the pull request.