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

loop_break_value: add documentation for book #41857

Merged
merged 5 commits into from
May 17, 2017
Merged
Changes from 2 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
79 changes: 79 additions & 0 deletions src/doc/unstable-book/src/language-features/loop-break-value.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,86 @@ The tracking issue for this feature is: [#37339]

[#37339]: https://github.com/rust-lang/rust/issues/37339

Documentation to be appended to section G of the book.

------------------------

### Loops as expressions

Like most things in Rust, loops are expressions; for example, the following is perfectly legal,
if rather useless:

```rust
let result = for n in 1..4 {
println!("Hello, {}", n);
};
assert_eq!(result, ());
```
Copy link
Contributor

@leoyvens leoyvens May 9, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't find this example very helpful in understanding the feature. The return value of for is a nice curiousity but I don't see much didatic value to this.


Until now, all the loops you have seen evaluate to either `()` or `!`, the latter being special
syntax for "no value", meaning the loop never exits. A `loop` can instead evaluate to
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't find the () vs ! distinction very useful, the meaning of ! as a type is unstable so maybe it's best to leave it out of this explanation.

a useful value via *break with value*:

```rust
// Find the first square number over 1000:
let mut n = 1;
let square = loop {
if n * n > 1000 {
break n * n;
}
n += 1;
};
```

The evaluation type may be specified externally:

```rust
// Declare that value returned is unsigned 64-bit:
let n: u64 = loop {
break 1;
};
```

It is an error if types do not agree, either between a "break" value and an external requirement,
or between multiple "break" values:

```rust
loop {
if random_bool() {
break 1u32;
} else {
break 0u8; // error: types do not agree
}
};

let n: i32 = loop {
break 0u32; // error: type does not agree with external requirement
};
```

For now, breaking with a value is only possible with `loop`; the same functionality may
some day be added to `for` and `while` (this would require some new syntax like
`while f() { break 1; } default { break 0; }`).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like that this speculates about future language extensions and their syntax.

Copy link
Contributor Author

@dhardy dhardy May 9, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I half agree with you here, but I think that if there is no mention of the discrepancy between loop and for/while that some readers will assume break-with-value also works there and confused why it doesn't work, and some will start asking the obvious why.

I suppose I could just omit the last bit about why for and while don't support break-with-value, but it still leaves an obvious question why.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Rust book already uses loop to refer to all three repetitive control-flow constructs:

Rust has three kinds of loops: loop, while, and for.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your concerns are valid, but the why response is complex and depends on who you ask, imo it's too opinionated to get into that here. I definitely think your use of the loop term is correct, I just worry it may be confusing in this context.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah; we don't say stuff like this in the docs because it often bitrots; then people think you can't do it when you actually can!


#### Break: label, value

Four forms of `break` are available, where EXPR is some expression which evaluates to a value:

1. `break;`
2. `break 'label;`
3. `break EXPR;`
4. `break 'label EXPR;`

When no value is given, the value `()` is assumed, thus `break;` is equivalent to `break ();`.

Using a label allows returning a value from an inner loop:

```rust
let result = 'outer: loop {
for n in 1..10 {
if n > 4 {
break 'outer n;
}
}
};
```