As a follow up to the throw
expressions proposal,
this strawman seeks to explore the feasability of defining expression-forms for other statements.
To frame this discussion and establish an overall scope for this proposal, at this time we are only
considering expression forms for a limited set of statements. As such, all declarations that do not
already have an expression form are out of scope for the purposes of this proposal, though they may
be explored in a later proposal.
Stage: 0
Champion: Ron Buckton (@rbuckton)
For more information see the TC39 proposal process.
- Ron Buckton (@rbuckton)
Simple statements are those ECMAScript statements that do not directly contain other statements
(throw
, return
, break
, continue
, debugger
). The completion semantics for these
statements are fairly trivial to convert to expression semantics. As a result, these simple
statements are the primary focus of this proposal.
throw
statements already have a proposal
for an expression form, allowing the following motivating use cases:
- 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"); } }
UnaryExpression[Yield, Await]:
`throw` UnaryExpression[?Yield, ?Await]
Allowing a return
in an expression position would allow for the early exit from a function while
in the midst of any expression:
function checkOpts(opts) {
let x = opts && opts.x || return false;
/* ...do something with x... */
}
UnaryExpression[Yield, Await]:
`return` UnaryExpression[?Yield, ?Await]
Allowing a break
in an expression position would allow for an immediate jump from within the
current expression to the end of the target LabelledStatement, SwitchStatement, or
IterationStatement:
switch (cond) {
case 0:
const y = x.y || break;
// ...do something with `y`...
break;
}
UnaryExpression[Yield, Await]:
BreakExpression
BreakExpression:
`break`
`break` [no |LineTerminator| here] LabelIdentifier
Allowing a continue
in an expression position would allow for an immediate jump to the next
iteration within an IterationStatement:
for (const x of array) {
const y = x.y || continue; // continue if `x.y` is not present.
}
UnaryExpression[Yield, Await]:
ContinueExpression
ContinueExpression:
`continue`
`continue` [no |LineTerminator| here] LabelIdentifier
Allowing a debugger
operation in an expression position would allow for an immediate break
into an attached debugger at the current expression:
const y = x.y || debugger; // break into debugger if `x.y` is not present.
UnaryExpression[Yield, Await]:
`debugger`
To avoid grammatical ambiguity, the above expressions are restricted from ExpressionStatement:
ExpressionStatement[Yield, Await]:
[lookahead ∉ {`{`, `function`, `async` [no |LineTerminator| here] `function`, `class`, `let [`,
`throw`, `return`, `break`, `continue`, `throw`, `debugger` }] Expression[+In, ?Yield, ?Await]
Compound statements are those statements that directly contain one or more other statement. This
category includes all control-flow statements (if
, switch
, try
), iteration statements (do
, while
, for
), with
statements, and blocks.
This category is not yet fully explored and requires further investigation to determine what syntax and semantics would best fit each of these kinds of statements if they were to have an expression form.
This is an area that closely overlaps with the do
expression proposal. A more thorough discussion
regarding what constitutes a usable completion value from these statements would best be handled as
part of that proposal.
Declaration statements are currently out-of-scope for this proposal, though they may be explored in a later proposal.