# Design \`?\` to work on named blocks

**URL:** <https://internals.rust-lang.org/t/design-to-work-on-named-blocks/7312>\
**Category:** language design\
**Created:** [April 14, 2018, 7:31pm UTC](https://internals.rust-lang.org/t/design-to-work-on-named-blocks/7312 "2018-04-14T19:31:18Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![repax](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/repax/32/1342_2.png) [@repax](https://internals.rust-lang.org/u/repax)\
**Post date:** [April 14, 2018, 7:31pm UTC](https://internals.rust-lang.org/t/design-to-work-on-named-blocks/7312/1 "2018-04-14T19:31:18Z")

</div>

An idea that I didn’t see discussed in the RFC #2046 (label-break-value) is to have the `?` operator do a `break`-with-value. Then you’d have the freedom to exit the outer function or any intermediary named block.

**There’s no need for either of `try` or `catch`**

```rust
fn foo() -> Result<T, E> {

    let r: Result<T, E> = 'a: {
        fallible()?.bar(); // exit fn
        fallible()'a?.bar(); // exit 'a
        ...
    }
    ...
}

```

But why only limit yourself to the innermost named block:

```rust
'outer: {
    'inner: {
        fallible(x)'outer?.bar();
    }
}

```

Coheres well with labelled blocks and loops. Example showing short-circuiting with a success value:

```rust
'a: {
    if (easy_condition) { break 'a 42; }
    ...
}

```

Early abort the `fn`:

```rust
'a: {
    if (bad_condition) { return; }
    ...
}

```

---

<div class="post-metadata">

**Author:** ![phaylon](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/phaylon/32/62_2.png) [@phaylon](https://internals.rust-lang.org/u/phaylon)\
**Post date:** [April 14, 2018, 8:39pm UTC](https://internals.rust-lang.org/t/design-to-work-on-named-blocks/7312/3 "2018-04-14T20:39:30Z")

</div>

I’m starting to feel this would be a more rusty and wholesome solution.

It would be nice since it keeps all type inference hints at the usual places.

Note: I think at some point it was proposed that `break 'fn` could be used to directly refer to the function scope. That would work for this solution as well.

---

<div class="post-metadata">

**Author:** ![Centril](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/centril/32/3334_2.png) [@Centril](https://internals.rust-lang.org/u/Centril)\
**Post date:** [April 14, 2018, 10:22pm UTC](https://internals.rust-lang.org/t/design-to-work-on-named-blocks/7312/4 "2018-04-14T22:22:10Z")

</div>

Some notes:

- If we did this, then `?` should by default short-circuit to the innermost labeled block; otherwise you’d get `'init` all over the place which would add significant noise and negate gains in ergonomics.
  - I’m not sure that could be done backwards-compatibly tho as you have `'foo: loop { .. }` already, so it would require edition breakage.
  - I suspect the edition breakage would not be extensive.

- This does not use Ok-wrapping and I don’t think it could.

Other than that it is interesting.

---

<div class="post-metadata">

**Author:** ![steven099](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/steven099/32/3871_2.png) [@steven099](https://internals.rust-lang.org/u/steven099)\
**Post date:** [April 14, 2018, 10:27pm UTC](https://internals.rust-lang.org/t/design-to-work-on-named-blocks/7312/5 "2018-04-14T22:27:34Z")

</div>

If you copy and paste the code somewhere, you have to update the labels, which doesn’t bode well for example code. And you’ll get shadowing warnings if the labels overlap with others in scope.

---

<div class="post-metadata">

**Author:** ![repax](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/repax/32/1342_2.png) [@repax](https://internals.rust-lang.org/u/repax)\
**Post date:** [April 14, 2018, 10:35pm UTC](https://internals.rust-lang.org/t/design-to-work-on-named-blocks/7312/6 "2018-04-14T22:35:49Z")

</div>

@steven099 Or you can argue the opposite is true: you’d avoid simple copy-paste errors. Named destinations can be safer as their names may carry intention and semantic meaning that can’t easily be expressed in plain block hierarchies.

---

<div class="post-metadata">

**Author:** ![repax](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/repax/32/1342_2.png) [@repax](https://internals.rust-lang.org/u/repax)\
**Post date:** [April 14, 2018, 10:51pm UTC](https://internals.rust-lang.org/t/design-to-work-on-named-blocks/7312/7 "2018-04-14T22:51:34Z")

</div>

@Centril Yes, I first proposed `?` to bubble up to the innermost named block but was unsure about what could be done about the current situation: label-break-value #2046 is accepted but not yet implemented or stable. Labelled loops (with values) are stable though. 😒

I don’t necessarily want a breaking edition charge if explicit labels aren’t that bad.

`try` and `catch` would require a breaking change, I suppose. But it’d be nicer without.

* * *

Anyhow, we already have `break` with value in the pipeline. So, it’d be virtuous to build upon that rather than adding a completely new and unrelated means of propagating values, I’d like to think.

---

<div class="post-metadata">

**Author:** ![kornel](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kornel/32/2711_2.png) [@kornel](https://internals.rust-lang.org/u/kornel)\
**Post date:** [April 14, 2018, 11:39pm UTC](https://internals.rust-lang.org/t/design-to-work-on-named-blocks/7312/8 "2018-04-14T23:39:08Z")

</div>

This looks cool, but I find having to come up with a name for every block problematic. Naming is hard, and I’m too lazy to make effort for every internal 2-3 lines of code. I’d probably write `'a` on all of them, or at best repeat the name of the variable they’re for:

```rust
let frob = 'frob: {
    fallible()'frob?.bar()
}

```

---

<div class="post-metadata">

**Author:** ![DDOtten](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ddotten/32/4334_2.png) [@DDOtten](https://internals.rust-lang.org/u/DDOtten)\
**Post date:** [April 15, 2018, 12:23am UTC](https://internals.rust-lang.org/t/design-to-work-on-named-blocks/7312/9 "2018-04-15T00:23:49Z")

</div>

I don’t think it would be bad to have some kind of default name like we have with `T` for a template type and `'a` for a lifetime. This could replace the proposed `try` with `'try` for example. (Or any other default name we end op choosing.)

---

<div class="post-metadata">

**Author:** ![Centril](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/centril/32/3334_2.png) [@Centril](https://internals.rust-lang.org/u/Centril)\
**Post date:** [April 15, 2018, 12:24am UTC](https://internals.rust-lang.org/t/design-to-work-on-named-blocks/7312/10 "2018-04-15T00:24:55Z")

</div>

> [@repax](#):
>
> try and catch would require a breaking change, I suppose. But it’d be nicer without.

In the case of `try` and `catch`, any breakage is easily rust-fixable tho. I'm not so sure it is as readily fixable for `'foo: loop { .. }`.

I'd say that having to specify the label in the common case as `fallible()'init?.bar()` is not an alternative to me. It is not very legible syntax either in comparison to `try { .. }`.

While I like the generality of your proposal, I'd also want to echo @kornel's sentiments on naming. I'd probably just go with `let quux = 'try: { foo()'try?.bar()'try?.baz() };` most of the time.

I also don't think it is quite common to nest like this and want to break out to different scopes, so while the generality is nice, the loss of Ok-wrapping feels like a bigger hit than what is gained.

Your proposal is also orthogonal to `try { .. }` in the sense that it is possible to have both and `try { .. }` seems more ergonomic for most common cases.

---

<div class="post-metadata">

**Author:** ![repax](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/repax/32/1342_2.png) [@repax](https://internals.rust-lang.org/u/repax)\
**Post date:** [April 15, 2018, 12:41am UTC](https://internals.rust-lang.org/t/design-to-work-on-named-blocks/7312/11 "2018-04-15T00:41:33Z")

</div>

For the other, but breaking, alternative of:

```rust
'a: {
    fallible()'fn?.bar(); // exit fn, explicitly
    fallible()'a?.bar(); // exit 'a, explicitly
    fallible()?.bar(); // exit whatever's innermost
    ...
}

```

the only breaking change, if I’m correct, is the case of using `?` from within a labelled loop:

```rust
'a: loop {
    fallible()?.bar();
    .... 
}

```

which already has a stable interpretation and implementation of exiting from the `fn`. This doesn’t apply to other labelled blocks though because they are not yet implemented or stable. So there exists no code like the following:

```rust
'a: {
    fallible()?.bar();
}

```

I don’t know how common it is to use `?` from whitin labelled loops, so I cannot estimate the amount of breakage. Perhaps not that bad?

The rustfix would be to automatically add `'fn` to `?` within loops.

---

<div class="post-metadata">

**Author:** ![rpjohnst](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/rpjohnst/32/9524_2.png) [@rpjohnst](https://internals.rust-lang.org/u/rpjohnst)\
**Post date:** [April 15, 2018, 1:28am UTC](https://internals.rust-lang.org/t/design-to-work-on-named-blocks/7312/12 "2018-04-15T01:28:08Z")

</div>

I would much rather the syntax for break-with-value (a relatively rare construct that already inspired some uneasiness about its effect on the legibility of control flow) and “break-with-error”/“break-with-special-case” (an extremely common construct in widespread use) remain completely separate.

---

<div class="post-metadata">

**Author:** ![Centril](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/centril/32/3334_2.png) [@Centril](https://internals.rust-lang.org/u/Centril)\
**Post date:** [April 15, 2018, 1:41am UTC](https://internals.rust-lang.org/t/design-to-work-on-named-blocks/7312/13 "2018-04-15T01:41:17Z")

</div>

> [@repax](#):
>
> Perhaps not that bad?

Probably not that bad, yes.

> [@repax](#):
>
> The rustfix would be to automatically add `'fn` to `?` within loops.

Sure, that works; However, it is predicated on introducing `'fn`.

---

<div class="post-metadata">

**Author:** ![hyeonu](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/hyeonu/32/2162_2.png) [@hyeonu](https://internals.rust-lang.org/u/hyeonu)\
**Post date:** [April 15, 2018, 2:03am UTC](https://internals.rust-lang.org/t/design-to-work-on-named-blocks/7312/14 "2018-04-15T02:03:24Z")

</div>

Why `expr?` breaks innermost by default? There’s no breakage if it breaks function by default.

For simpler local try, allow block labels to shadow outer ones is sufficient, and I think its more rusty. We can teach that `'try: { .. }` is the de-facto syntax for local try block.

---

<div class="post-metadata">

**Author:** ![Centril](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/centril/32/3334_2.png) [@Centril](https://internals.rust-lang.org/u/Centril)\
**Post date:** [April 15, 2018, 2:52am UTC](https://internals.rust-lang.org/t/design-to-work-on-named-blocks/7312/15 "2018-04-15T02:52:15Z")

</div>

> [@hyeonu](#):
>
> Why expr? breaks innermost by default? There’s no breakage if it breaks function by default.

Because if it does not break the innermost label by default, then you'll have to litter every `?` with `'label?` to get the same behavior as `try { .. }`. An example:

```rust
let result: Result<Foo, MyError> = 'try: {
    let x = alpha()'try?;
    let y = beta(x)'try?;
    let z = gamma(y)'try?;
    delta(z)
}

```

This version with `'try` is more fair since people should not use one-letter names. But since it introduces significant noise, I think it will lead to the following instead:

```rust
let result: Result<Foo, MyError> = 'a: {
    let x = alpha()'a?;
    let y = beta(x)'a?;
    let z = gamma(y)'a?;
    delta(z)
}

```

This still has noise that is in the way and is not terribly readable wrt. intent.

Compare this to:

```rust
let result: Result<Foo, MyError> = try {
    let x = alpha()?;
    let y = beta(x)?;
    let z = gamma(y)?;
    delta(z)?
}

```

In this version, there is no added noise, and I think it helps the much more common case while also being clear with respect to intent.

---

<div class="post-metadata">

**Author:** ![hyeonu](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/hyeonu/32/2162_2.png) [@hyeonu](https://internals.rust-lang.org/u/hyeonu)\
**Post date:** [April 15, 2018, 3:10am UTC](https://internals.rust-lang.org/t/design-to-work-on-named-blocks/7312/16 "2018-04-15T03:10:16Z")

</div>

One possible choice is to make ?op escapes the label 'try by default, and implicitly label every function block as 'try.

Yes, I also think this is too magical. And it definitely breaks code that labels loop with 'try.

This idea leads me here: can we make that `try { .. }` as a syntactic-sugar-like? With this idea, every functions have unnamed label that traps non-labeled ?op and the try block is the only way to use this unnamed label.

I’m still not sure if this can be generalized to labeled break and loops. Thoughts?

---

<div class="post-metadata">

**Author:** ![phaylon](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/phaylon/32/62_2.png) [@phaylon](https://internals.rust-lang.org/u/phaylon)\
**Post date:** [April 15, 2018, 3:23am UTC](https://internals.rust-lang.org/t/design-to-work-on-named-blocks/7312/17 "2018-04-15T03:23:54Z")

</div>

> [@Centril](#):
>
> Because if it does not break the innermost label by default, then you’ll have to litter every ? with 'label? to get the same behavior as try { .. }.

The advantage would be that every jump that isn't out of the function would be visible at jump-site. And bailout macros could take an optional label at start to allow specifying what they're bailing out of.

---

<div class="post-metadata">

**Author:** ![Centril](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/centril/32/3334_2.png) [@Centril](https://internals.rust-lang.org/u/Centril)\
**Post date:** [April 15, 2018, 3:32am UTC](https://internals.rust-lang.org/t/design-to-work-on-named-blocks/7312/18 "2018-04-15T03:32:37Z")

</div>

> [@phaylon](#):
>
> The advantage would be that every jump that isn’t out of the function would be visible at jump-site.

I don't particularly like to repeat myself in code. So to me, it isn't an advantage at all. It is just repetitive noise.

> [@phaylon](#):
>
> And bailout macros could take an optional label at start to allow specifying what they’re bailing out of.

You could still allow the explicitly labeled version which would still allow macros to take an optional label.

I think it is entirely feasible technically to permit `try { alpha()?.beta()? }` and `'lab: { alpha()'lab?.beta() }`, but I suspect the usefulness will be limited once you have `try { .. }`.

There's also the question of whether the label should be prefix: `foo()'lab?.bar` or postfix: `foo()?'lab.bar`. Neither option seems particularly obvious to me.

---

<div class="post-metadata">

**Author:** ![phaylon](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/phaylon/32/62_2.png) [@phaylon](https://internals.rust-lang.org/u/phaylon)\
**Post date:** [April 15, 2018, 4:01am UTC](https://internals.rust-lang.org/t/design-to-work-on-named-blocks/7312/19 "2018-04-15T04:01:15Z")

</div>

> [@Centril](#):
>
> I don’t particularly like to repeat myself in code. So to me, it isn’t an advantage at all. It is just repetitive noise.

Yeah, I'm more the kind that tries to label every break or continue unless it's a really small `fn`.

---

<div class="post-metadata">

**Author:** ![repax](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/repax/32/1342_2.png) [@repax](https://internals.rust-lang.org/u/repax)\
**Post date:** [April 15, 2018, 7:30am UTC](https://internals.rust-lang.org/t/design-to-work-on-named-blocks/7312/20 "2018-04-15T07:30:55Z")

</div>

### A small comparison

Let’s compare the three main proposals discussed in this thread. The exception style syntax is simple but less capable. It also introduces a new concept (`try` or `catch` blocks). The blocky style variants reuse existing Rust features instead and give you more control over where to bubble values, and can bubble up both failures and success values. There’s a short and implicit variant, others might value the explicitness of the other variant.

Some might find the exceptional style familiar, others might find it confusing because it’s not exactly the same as in other languages. The blocky variants do not use exceptional terminology of either `try` or `throw`.

#### try {}

```rust
try {
    fallible()?;
}

```

| | |
| --- | --- |
| edition breaking change | **yes** |
| automatic rustfix | rename instances to `r#try` |
| known conflicts | `try!` macro in code/docs/forums/blogs… |
| syntax | exceptional style |
| propagate error to innermost | `(...)?` |
| propagate error to outer block | _N/A_ |
| propagate error to function | _N/A_ |
| short-circuit success to innermost | _N/A_ |
| short-circuit success to outer block | _N/A_ |

Main benefits:

- _syntax is short_
- _automatic Ok-wrapping_  
  

* * *

#### explicit blocky `?` – the main contender

```rust
'a {
    fallible()'a?;
}

```

| | |
| --- | --- |
| edition breaking change | **no** |
| automatic rustfix | |
| known conflicts | |
| syntax | reuse blocks |
| propagate error to innermost | `(...)'a?` |
| propagate error to outer block | `(...)'b?` |
| propagate error to function | `(...)?` |
| short-circuit success to innermost | `break 'a 42;` |
| short-circuit success to outer block | `break 'b 42;` |

Main benefits:

- _No breaking change!_
- _The most common case of propagating to `fn`, is short_: `(EXPR)?`
- Less implicitness and hidden conversions at block boundaries
- Coheres well with labelled `break`, `continue` and `loop`  
  

* * *

#### implicit blocky `?`

```rust
'a {
    fallible()?;
}

```

| | |
| --- | --- |
| edition breaking change | **yes** |
| automatic rustfix | add `'fn` to `?` only in labelled loops |
| known conflicts | |
| syntax | reuse blocks |
| propagate error to innermost | `(...)?` |
| propagate error to outer block | `(...)'b?` |
| propagate error to function | `(...)'fn?` |
| short-circuit success to innermost | `break 'a 42;` |
| short-circuit success to outer block | `break 'b 42;` |

Main benefits compared to the exceptional style:

- Just as short: `(EXPR)?`
- More capable
- Less implicitness and hidden conversions at block boundaries

---

<div class="post-metadata">

**Author:** ![repax](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/repax/32/1342_2.png) [@repax](https://internals.rust-lang.org/u/repax)\
**Post date:** [April 15, 2018, 7:59am UTC](https://internals.rust-lang.org/t/design-to-work-on-named-blocks/7312/21 "2018-04-15T07:59:48Z")

</div>

> [@Centril](#):
>
> ```rust
> let result: Result<Foo, MyError> = 'a: {
> let x = alpha()'a?;
> let y = beta(x)'a?;
> let z = gamma(y)'a?;
> delta(z)
> }
> 
> ```
> 
> This still has noise that is in the way and is not terribly readable wrt. intent.

To be honest, it doesn't look _that_ unreadable to me. And the intent is certainly clear.

The more common case in practice is probably to exit the function and then you just write: `alpha()?;`

[Next page](https://internals.rust-lang.org/t/design-to-work-on-named-blocks/7312.md?page=2)
