-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Introduce var
/let
-else
-statement
#1871
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
# Introduce `var`/`let`-`else`-statement | ||
|
||
<!-- | ||
Part of the Carbon Language project, under the Apache License v2.0 with LLVM | ||
Exceptions. See /LICENSE for license information. | ||
SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
--> | ||
|
||
[Pull request](https://github.com/carbon-language/carbon-lang/pull/1871) | ||
|
||
<!-- toc --> | ||
|
||
## Table of contents | ||
|
||
- [Problem](#problem) | ||
- [Background](#background) | ||
- [Proposal](#proposal) | ||
- [Details](#details) | ||
- [Rationale](#rationale) | ||
- [Alternatives considered](#alternatives-considered) | ||
- [Unresolved questions](#unresolved-questions) | ||
|
||
<!-- tocstop --> | ||
|
||
## 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) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you instead add the actual pull so that our reviewers can feel the impression at that time? |
||
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. | ||
Comment on lines
+52
to
+53
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It would be great to go deeper into this here. |
||
|
||
## 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. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. RFC - Request For Comment Hence C is Comment(s). Like yours. ;) |
||
|
||
## 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. | ||
Comment on lines
+90
to
+92
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Rationales in Carbon are to be written in terms of Carbon's stated goals and principles. The proposal template has some links, the one that I think is relevant to this proposal is: |
||
|
||
## Alternatives considered | ||
|
||
- `var`/`let` ... `or {...}` | ||
- `var`/`let` ... `?: {...}` a short-circuited ternary operator | ||
- `var`/`let` ... `otherwise {...}` | ||
- introducer syntax: `guard var`/`let` ... `else {...}` | ||
Comment on lines
+96
to
+99
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These alternatives should include the advantages and disadvantages of these options and a rationale for why we chose the proposal over the alternative. If you don't know, that is a good time to reach out to the community. |
||
|
||
## Unresolved questions | ||
|
||
- How often is this pattern actually used? | ||
- Is it really more readable? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a problem, otherwise we should not pursue this proposal. I believe
var
/let
-else
solves a real problem, and it is important that this proposal articulate what that problem is. The problem has to do with making common programming tasks both readable and writable. The specific benefit ofvar
/let
-else
is when the task has two cases:If code follows that pattern, then this construct has two advantages: it is concise and not going to introduce as much indenting as other constructs. Both of these help readability and writability. Consider:
compared to:
The big question is whether this use case is important / common. And I think that comes down to looking at examples when you would use this construct. I think the "function returns an optional" situation is one common example where this comes up. Another example is when calling a function that returns an error that this function wants to transform into a different error. Other examples would be valuable to identify.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You might want to search around for the "return early pattern" to find examples where this would be useful.