diff --git a/proposals/p1871.md b/proposals/p1871.md new file mode 100644 index 0000000000000..4aefb7c82df3c --- /dev/null +++ b/proposals/p1871.md @@ -0,0 +1,104 @@ +# Introduce `var`/`let`-`else`-statement + + + +[Pull request](https://github.com/carbon-language/carbon-lang/pull/1871) + + + +## Table of contents + +- [Problem](#problem) +- [Background](#background) +- [Proposal](#proposal) +- [Details](#details) +- [Rationale](#rationale) +- [Alternatives considered](#alternatives-considered) +- [Unresolved questions](#unresolved-questions) + + + +## Problem + +This statement is syntactic sugar for a set of other patterns, specifically it +guards a code block if a requirement of this code block is violated. That is, +there is actually no problem. + +## Background + +The idea goes back to the prior art in +[Swift](https://docs.swift.org/swift-book/LanguageGuide/ControlFlow.html#ID525) +to allow the execution of a statement depending on the Boolean value of an +expression. Swift used a **guard** statement to require that a condition must be +true in order for all following code in the current code block to be executed. +If the condition is not true, control needs to be transferred using a control +transfer statement as `break`, `continue`, `return`, or a function that does not +return. + +[Rust](https://github.com/rust-lang/rfcs/blob/master/text/3137-let-else.md) +followed suit and introduced the **let-else statement**: + +```rust +let PATTERN: TYPE = EXPRESSION else DIVERGING_BLOCK; +``` + +as a more or less natural counterpart to its +[if-let expression](https://github.com/rust-lang/rfcs/blob/master/text/0160-if-let.md). + +This proposal adds this pattern as it seems to be rather popular and simplifies +common error-handling patterns. + +## Proposal + +A `let` or `var` declaration may be used with a +[refutable pattern](https://github.com/carbon-language/carbon-lang/blob/trunk/docs/design/README.md#refutable-patterns) +if an `else` clause is supplied, as in: + +```carbon +let (x: i32, true) = F(1) else { + // Can't use `x` here. + return false; +} +// `x` is an r-value +var (y: i32, true) = F(x) else { + return false; +} +// `y` is an l-value +y += 2; +``` + +If the pattern successfully matches the runtime value, values are bound +according to the pattern, and execution skips over the `else` code block and +proceeds to the next statement. + +If the pattern does not match, the `else` code block will be executed. None of +the bindings from the pattern will be in scope in the `else` code block. No +control flow path in the `else` code block may continue to the statement after. +All paths must end with a `break`, `continue`, `return`, or call to a function +that never returns. + +## Details + +TBD after enough C in this RFC. + +## Rationale + +This pattern is said to improve the readability of code, compared to an +equivalent `match` or `if` statement. It allows to keep code which handles +violated requirements next to the requirements. + +## Alternatives considered + +- `var`/`let` ... `or {...}` +- `var`/`let` ... `?: {...}` a short-circuited ternary operator +- `var`/`let` ... `otherwise {...}` +- introducer syntax: `guard var`/`let` ... `else {...}` + +## Unresolved questions + +- How often is this pattern actually used? +- Is it really more readable?