# Automatic "?" inside try {...} blocks

**URL:** <https://internals.rust-lang.org/t/automatic-inside-try-blocks/7507>\
**Category:** language design\
**Created:** [May 11, 2018, 7:12am UTC](https://internals.rust-lang.org/t/automatic-inside-try-blocks/7507 "2018-05-11T07:12:29Z")\
**Posts on this page:** 1\
**Showing post:** 28

<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:** [May 13, 2018, 3:13pm UTC](https://internals.rust-lang.org/t/automatic-inside-try-blocks/7507/28 "2018-05-13T15:13:15Z")

</div>

On the other hand, having _some_ context in which errors are propagated implicitly would open the door to an interesting kind of polymorphism- call it “`try`-polymorphism.” The very same behavior that @josh is concerned about—a function call starting to propagate an error without the caller making a decision on how to handle it—would be quite useful in functions that take and call closures.

For example, look at the `unwrap_or_else` function. Its closure argument _must_ return the same type as the `Result`'s `T` argument. Which means if you want to use `?`, you have to write something like this:

```rust
some_result.map(Ok).unwrap_or_else(|err| {
    let foo = look_something_up()?;
    Ok(transform(foo))
})?

```

Note the extra `.map(Ok)` and the double `?`. This has to be worked through, ad-hoc, for every combinator you might use. If we made `try fn`s implicitly propagate the errors of other `try fn`s they call, and made those combinators `try`-polymorphic based on their closure argument, you might instead write this:

```rust
some_result.unwrap_or_else(try |err| {
    let foo = look_something_up();
    transform(foo)
})

```

This is also doable without the implicit propagation, but it would make writing `try`-polymorphic functions kind of odd- what would be the type of a function call expression that _may or may not_ be `try`? We’d have to extend `try`-polymorphism from functions to values. And then `?` would have to operate on those `?Result`s as well as on `Result`s.

This is far more important for `Future`s, where you can’t just `.map(future::ok)` because that results in a _different_ `Future` type than the `async` closure. You would actually have to use a completely separate combinator function that takes `async` closures! And a “polymorphic value” of type `?Future<Output=T>` is even weirder than the above `?Result<T>`- the `async`-polymorphic combinator’s choice of where to `?await!` would change the _order_ of execution, not just where it early-exits.

I doubt this polymorphism is worth that complexity at the value level, but the complexity at the function level is _far_ less. C++ already has it in the form of `noexcept` expressions, which they use to e.g. select a faster algorithm for `std::vector` resizing when the element is `noexcept`-movable. And I _know_ we’ve all run into the desire to write `?` in a closure before.

---

_[View the full topic](https://internals.rust-lang.org/t/automatic-inside-try-blocks/7507)._
