Skip to content
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

RFC for while let statement #214

Merged
merged 3 commits into from
Oct 1, 2014
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 84 additions & 0 deletions active/0000-while-let.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
- Start Date: 2014-08-27
- RFC PR: (leave this empty)
- Rust Issue: (leave this empty)

# Summary

Introduce a new `while let PAT = EXPR { BODY }` construct. This allows for using a refutable pattern
match (with optional variable binding) as the condition of a loop.

# Motivation

Just as `if let` was inspired by Swift, it turns out Swift supports `while let` as well. This was
not discovered until much too late to include it in the `if let` RFC. It turns out that this sort of
looping is actually useful on occasion. For example, the desugaring `for` loop is actually a variant
on this; if `while let` existed it could have been implemented to map `for PAT in EXPR { BODY }` to

```rust
// the match here is so `for` can accept an rvalue for the iterator,
// and was used in the "real" desugaring version.
match &mut EXPR {
i => {
while let Some(PAT) = i.next() {
BODY
}
}
}
```

(note that the non-desugared form of `for` is no longer equivalent).

More generally, this construct can be used any time looping + pattern-matching is desired.

This also makes the language a bit more consistent; right now, any condition that can be used with
`if` can be used with `while`. The new `if let` adds a form of `if` that doesn't map to `while`.
Supporting `while let` restores the equivalence of these two control-flow constructs.

# Detailed design

`while let` operates similarly to `if let`, in that it desugars to existing syntax. Specifically,
the syntax

```rust
['ident:] while let PAT = EXPR {
BODY
}
```

desugars to

```rust
['ident:] loop {
match EXPR {
PAT => BODY,
_ => break
}
}
```

Just as with `if let`, an irrefutable pattern given to `while let` is considered an error. This is
largely an artifact of the fact that the desugared `match` ends up with an unreachable pattern,
and is not actually a goal of this syntax. The error may be suppressed in the future, which would be
a backwards-compatible change.

Just as with `if let`, `while let` will be introduced under a feature gate (named `while_let`).

# Drawbacks

Yet another addition to the grammar. Unlike `if let`, it's not obvious how useful this syntax will
be.

# Alternatives

As with `if let`, this could plausibly be done with a macro, but it would be ugly and produce bad
error messages.

`while let` could be extended to support alternative patterns, just as match arms do. This is not
part of the main proposal for the same reason it was left out of `if let`, which is that a) it looks
weird, and b) it's a bit of an odd coupling with the `let` keyword as alternatives like this aren't
going to be introducing variable bindings. However, it would make `while let` more general and able
to replace more instances of `loop { match { ... } }` than is possible with the main design.

# Unresolved questions

None.