# Pre-RFC: flexible \`try fn\`

**URL:** <https://internals.rust-lang.org/t/pre-rfc-flexible-try-fn/7564>\
**Category:** Uncategorized\
**Created:** [May 17, 2018, 11:49pm UTC](https://internals.rust-lang.org/t/pre-rfc-flexible-try-fn/7564 "2018-05-17T23:49:27Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![newpavlov](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/newpavlov/32/3290_2.png) [@newpavlov](https://internals.rust-lang.org/u/newpavlov)\
**Post date:** [May 17, 2018, 11:49pm UTC](https://internals.rust-lang.org/t/pre-rfc-flexible-try-fn/7564/1 "2018-05-17T23:49:27Z")

</div>

This approach is a bit extreme, but, I think, worth exploring.

Relevant topics:

- [RFC2426: `throw` expressions](https://github.com/rust-lang/rfcs/pull/2426)
- [Pre-RFC: Catching Functions](https://internals.rust-lang.org/t/pre-rfc-catching-functions/6505)

UPD: If you don’t want to read the whole discussion I recommend to check this @Centril’s [comment](https://internals.rust-lang.org/t/pre-rfc-flexible-try-fn/7564/67).

# Summary

Introduce `try fn` and `throw`/`fail`/etc. keyword (`throw` will be used here for now), which will allow us to write the following code:

```rust
try fn foo() -> Result<u64, MyError> {
    // returns Ok(10), i.e. happy path is Ok autowrapped
    if early_return() { return 10; }
    // returns `Err(MyError)`
    if is_error() { throw MyError; }
    // `?` works as well
    check_another_error()?;
    1 
}

try fn bar() -> Result<(), MyError> {
    if is_error() { throw MyError; }
    // Good buy `Ok(())`!
}

```

Additionally `try fn` will work with `Option` and even custom types which will implement `TryOk` and `TryThrow`.

# How it will work

Instead of [`Try`](https://doc.rust-lang.org/std/ops/trait.Try.html) trait we will have the following two traits:

```rust
trait TryOk<T> {
    fn from_ok(val: T) -> Self;
}

trait TryThrow<T> {
    fn from_throw(val: T) -> Self;
}

```

And `Result` will have the following implementations:

```rust
impl<T, E> TryOk<T> for Result<T, E> {
    fn from_ok(val: T) -> Self { Ok(val) }
}

impl<T, E, V: Into<E>> TryThrow<V> for Result<T, E> {
    fn from_throw(val: V) -> Self { Err(val.into()) }
}

```

Now this code:

```rust
try fn foo() -> Result<u64, MyError> {
    if is_error() { throw MyError; }
    1 
}

```

Will be desugared into:

```rust
fn foo() -> Result<u64, MyError> {
    if is_error() { return TryThrow::from_throw(MyError); }
    TryOk::from_ok(1)
}

```

For `Option` trait implementations will look like:

```rust
impl<T> TryOk<T> for Option<T> {
    fn from_ok(val: T) -> Self { Some(val) }
}

impl<T> TryThrow<()> for Option<T> {
    fn from_throw(_val: ()) -> Self { None }
}

```

# Why generic type in traits instead of the associated one?

For `Result` and `Option` generic type in the `Try` traits is clearly redundant, but with custom types it can lead to boilerplate reduction and ergonomic improvements. For example this can be in a crate:

```rust
enum Record {
    Int(i64),
    Str(String),
    Error(MyErr),
    None,
}

impl TryOk<i64> for Record {
    fn from_ok(val: i64) -> Self { Record::Int(val) }
}

impl TryOk<String> for Record {
    fn from_ok(val: String) -> Self { Record::Str(val) }
}

impl TryOk<i64> for Record {
    fn from_ok(val: i64) -> Self { Record::Int(val) }
}

impl<E, T: Into<E>> TryThrow<E> for Record {
    fn from_throw(val: T) -> Self { Record::Err(val.into()) }
}

impl TryThrow<()> for Record {
    fn from_throw(_val: ()) -> Self { Record::None }
}

```

And this in user code:

```rust
try fn foo(data: &[u8]) -> Record {
    if data.len() == 0 { throw; } // returns `Record::None`
    if let Err(e1) = check(data) { throw e1; } // e1 converted to MyErr
    if let Some(s) = parse_str(data) { return s; } // returns `Record::Str(s)`
    if let Some(n) = parse_int(data) { return n; } // returns `Record::Int(n)`
    throw "failure message";
}

```

There is (initially unintended) side-effect: type can implement only `TryOk` trait, e.g. like this:

```rust
impl<T: Into<Foo>> TryOk<T> for Foo {
    fn from_ok(val: T) -> Self { val.into() }
}
// no `TryThrow` implementations for `Foo`

```

Which will make `try fn`s returning `Foo` “auto-into” functions:

```rust
// converts `1` and `"ok"` into `Foo` automatically
try fn foo1() -> Foo {
    if true { return 1; }
    return "ok";
}

try fn foo2() -> Foo {
    throw; // compilation error: `Foo` does not implement `TryThrow` trait
}

```

# Drawbacks

- Overly-flexibile for the main use-cases (`Result` and `Option`).
- Can lead to surprising conversions behind the scenes.
- “Auto-into” variant is a bit surprising usage of `try fn`.

# Unresolved questions

## Bikeshed of trait and keyword names

This feature is closely related to the `throw` [RFC](https://github.com/rust-lang/rfcs/pull/2426) and has the same choices for keywords. Subjectively `throw MyError;` looks more natural than `fail MyError;`, thus I think it’s a slightly better option, even considering unwanted relation to exceptions.

## Special keyword for “happy” return

It was proposed to add `pass` keyword to the language, instead of doing autowrapping returns. The big disadvantages are:

- Additional keyword
- Return of `Ok(())`

## More magic in trait implementations

There is an open question of how far we want to go with traits implementations for `Result` and `Option`, e.g. the following implementation can be added:

```rust
impl<T, E, V: Into<T>> TryOk<V> for Result<T, E> {
    fn from_ok(val: V) -> Self { Ok(val.into()) }
}

```

Personally I think such implementations are unnecessary, and can result in too much confusion, compared to potential ergonomic improvements.

## Relation to `try` block

Try blocks are closely related to `try fn`s, thus ideally we would like to be able to think about `try fn foo() -> T { .. }` as a short-cut for `fn foo() -> T { try { .. } }`.

---

<div class="post-metadata">

**Author:** ![CAD97](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cad97/32/3460_2.png) [@CAD97](https://internals.rust-lang.org/u/CAD97)\
**Post date:** [May 18, 2018, 12:04am UTC](https://internals.rust-lang.org/t/pre-rfc-flexible-try-fn/7564/2 "2018-05-18T00:04:03Z")

</div>

What’s your reasoning for splitting `TryOk`/`TryThrow` into two traits? Are they both required for a try fn? If so, it would probably be better to just have one trait, `Try<Return, Throw>`, than two.

---

<div class="post-metadata">

**Author:** ![newpavlov](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/newpavlov/32/3290_2.png) [@newpavlov](https://internals.rust-lang.org/u/newpavlov)\
**Post date:** [May 18, 2018, 12:13am UTC](https://internals.rust-lang.org/t/pre-rfc-flexible-try-fn/7564/3 "2018-05-18T00:13:07Z")

</div>

Take `Record` example, how do you see `Try<Return, Throw>` implemented for it? Also it allows type to implement only one trait if needed.

---

<div class="post-metadata">

**Author:** ![CAD97](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cad97/32/3460_2.png) [@CAD97](https://internals.rust-lang.org/u/CAD97)\
**Post date:** [May 18, 2018, 1:43am UTC](https://internals.rust-lang.org/t/pre-rfc-flexible-try-fn/7564/4 "2018-05-18T01:43:05Z")

</div>

Ah, right, because it’s a many-many relationship between return-cases and throw-cases.

But what would implementing just one mean? Would this then be `return` coercion with `TryReturn` and `throw` coercion with `TryThrow`?

Could you have a `fn -> Return` where `Return <: ThyThrow, !TryReturn`?

---

<div class="post-metadata">

**Author:** ![newpavlov](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/newpavlov/32/3290_2.png) [@newpavlov](https://internals.rust-lang.org/u/newpavlov)\
**Post date:** [May 18, 2018, 2:06am UTC](https://internals.rust-lang.org/t/pre-rfc-flexible-try-fn/7564/5 "2018-05-18T02:06:17Z")

</div>

> [@CAD97](#):
>
> Would this then be `return` coercion with `TryReturn` and `throw` coercion with `TryThrow` ?

Yes, it will be.

And yes, technically it will be possible to create types which implement only `TryThrow`. If `try fn` returns such type, the only way to "return" something from this function will be through `throw`, which seems quite useless. Ideally we would like to put restriction on `TryThrow` "can be implemented only if at least one `TryOk` implementation exists", but AFAIK we can't express it in the current Rust.

---

<div class="post-metadata">

**Author:** ![scottmcm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/scottmcm/32/2355_2.png) [@scottmcm](https://internals.rust-lang.org/u/scottmcm)\
**Post date:** [May 18, 2018, 6:26am UTC](https://internals.rust-lang.org/t/pre-rfc-flexible-try-fn/7564/6 "2018-05-18T06:26:53Z")

</div>

I don’t think this is “extreme” at all – I was planning on writing something very similar once the initial `async fn` and `try {}` implementations landed in the compiler.

More prior art:

- [RFC #2107, Ok wrapping: Improved support for writing code from an error handling mindset](https://github.com/rust-lang/rfcs/pull/2107)
- [Pre-RFC: Throwing Functions](https://internals.rust-lang.org/t/pre-rfc-throwing-functions/5419?u=scottmcm)

My proposed direction: **`async` and `try` are both effects, and should work similarly**

- You never _need_ to use `async` nor `try` nor `await` nor `?`; you can use combinators instead, or call methods, or just `match`, or implement the traits directly
- You “undo” `async` with `await`; you “undo” `try` with `?`
- Both have carrier types: For `async`/`await` [it’s](https://github.com/rust-lang/rfcs/pull/2418) `impl Async<Output = T>`; for `try`/`?` [today it’s](https://doc.rust-lang.org/nightly/core/ops/trait.Try.html) `impl Try<Ok = T>` (though [likely to change](https://github.com/rust-lang/rust/issues/42327#issuecomment-366840247) – see below – [maybe](https://internals.rust-lang.org/t/bikeshed-a-consise-verb-for-the-operator/7289/57?u=scottmcm) `impl Bubble<Output = T>`)
- There are both “delayable” effects: you can call `foo()` at one point – maybe not even in `async`/`try` context – then `await`/`?` it later
  - (In comparison, `const` and `unsafe` don’t have carrier types and can’t be delayed – you of course can’t do `let x = foo(); let y = unsafe { x };` the way you can do `let x = foo() let y = x?;` or `let x = foo(); let y = await!(x);`)

- Today we have `.try_from()` and `TryFrom` naming conventions where there’s conflicts with infallible; I wouldn’t be surprised to also get `.read_async()` and `ReadAsync` naming conventions where there’s conflicts with synchronous
- Accepted RFCs have it so that you can use an `async {}` block to write asynchronous code in “similar to synchronous” style, and so that you can use a `try {}` block to write fallible code in “similar to infallible” style, with explicit markers in both cases for the things that are actually `async`/`try`
  - (Note that “what happens with `return` in a `try` block?” was a point of contention in the `try` RFC, and it’s just not allowed in an `async` block, so one simple and can-always-be-loosened-later option would be to prohibit it in `try` blocks too, initially.)

- If a whole function or closure wants that style, then it can be defined as `async fn` or `async ||`, and, I would propose `try fn` or `try ||`
  - The `async` RFC [decided](https://github.com/rust-lang/rfcs/blob/master/text/2394-async_await.md#the-order-of-async-and-move) that it’s `async move ||`, so it should also be `try move ||`

- The body of such a function, block, or closure is automatically wrapped in the appropriate carrier type – it’s `async { 4 }` or `try { 4 }`, not `async { Poll::Ready(4) }` or `try { Some(4) }` – including a `return` expression in a function or closure

One difference is that `await` is only allowed in a context that’s explicitly been marked `async`, whereas `?` can be used with just a compatible return type. We certainly shouldn’t remove that immediately, but I’d definitely be in favour of an opt-in clippy lint to block use of `?` outside of `try`, because today `?` is more than a fallibility marker, it’s also a “I’m thinking of the code here in the success-is-continue model”. And I think that an individual call is the wrong granularity for that choice: it should be a block (including, perhaps, the block that’s the body of a function). I personally find something like `return Err(foo()?)` dissonant, since the `?` implies that continuing on is success, but then it’s not. (I also wonder if those opposed to `?` would be less so if there was `try` as a “warning, you should expect `?`s in here” marker around any use thereof.)

Similarly, I think it would make sense to start with a `throw` expression that’s allowed _only_ in `try` context, since that immediately gets rid of the “when should I write `throw x` instead of `return Err(x)` question”. Whether it would stay that way I don’t know, though, since @Centril pointed out that it makes it harder to use in a broadly-applicable macro.

The other big question is how to write return types. RFC 2394 calls it a [“complicated question”](https://github.com/rust-lang/rfcs/blob/master/text/2394-async_await.md#the-return-type-t-instead-of-impl-futureoutput--t), ending up picking `-> T` instead of `-> impl Async<Output=T>` because of lifetime elision implications and a lack of need for polymorphic return. I’ve yet to see a `-> T throws E` syntax I’m happy with, so prefer just `-> Result<T, E>`. Interestingly, I think `try` hits exactly the opposite arguments as `async` here: a `try fn` doesn’t need to capture all the input lifetimes, so there aren’t the same gotchas with the full type, and since `?`and `try{}` are polymorphic today, I think it’s important for a `try fn` to also support non-Result return types.

As for the traits, see the [`try_trait` tracking issue](https://github.com/rust-lang/rust/issues/42327). Specifically, [this comment for your `TryOk`](https://github.com/rust-lang/rust/issues/42327#issuecomment-379156320) and [this comment for your `TryThrow`](https://github.com/rust-lang/rust/issues/42327#issuecomment-380650914). They’re roughly similar, though with some different choices around associated types and bounds to achieve goals like "`typeof(x?)` depends only on `typeof(x)`, not on context". (And note the mention of [“try functions”](https://github.com/rust-lang/rust/issues/42327#issuecomment-376772143) in that thread as well 🙂)

_(Oh man, that came out way longer than I was expecting…)_

---

<div class="post-metadata">

**Author:** ![newpavlov](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/newpavlov/32/3290_2.png) [@newpavlov](https://internals.rust-lang.org/u/newpavlov)\
**Post date:** [May 18, 2018, 6:48am UTC](https://internals.rust-lang.org/t/pre-rfc-flexible-try-fn/7564/7 "2018-05-18T06:48:15Z")

</div>

Great comment!

I’ve called the proposed approach “a bit extreme”, due to the (usually unneeded) flexibility introduced by using generic type parameter instead of the associated type in the `Try` traits. Regarding return type we can’t use `-> T throws E`, because we would like for this feature to work at least with `Option<T>` and ideally with custom types as well, so this is why I think using an exterior type for `try fn`s is the most sensible choice.

As for forbidding `?` outside of the `try` contexts, I think it’s an interesting option, which is definitely will be worth exploring after stabilization of `try` language features as preparation to the post-2018 epoch.

---

<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:** [May 18, 2018, 8:05am UTC](https://internals.rust-lang.org/t/pre-rfc-flexible-try-fn/7564/8 "2018-05-18T08:05:37Z")

</div>

For `Return` this changes

- `return Ok(x)` into `return x`;
- `return Err(y)` into `throw y`;

and to be honest I don’t really think that would be an improvement at all. This would create two different ways of doing things without becoming more readable or more ergonomic. This would also allow another thing before `fn` with would lead to things like `unsafe const async try fn` where it would be very hard to remember the order these things should go in.

To be honest I am against `Ok` wrapping in general because it reduces local reasoning and increases the complexity of the language just to save 4 characters, including the braces.

I also think that @repax’s [named block proposal](https://internals.rust-lang.org/t/design-to-work-on-named-blocks/7312) is a beter option than adding the `try` keyword mostly because it uses an existing underused language feature instead of adding an entirely new thing. It also really fits with the way other returns allow you to use labels.

---

<div class="post-metadata">

**Author:** ![bill\_myers](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/bill_myers/32/4085_2.png) [@bill\_myers](https://internals.rust-lang.org/u/bill_myers)\
**Post date:** [May 18, 2018, 11:18am UTC](https://internals.rust-lang.org/t/pre-rfc-flexible-try-fn/7564/9 "2018-05-18T11:18:17Z")

</div>

For the return types problem, one could have syntax like this:

```rust
async(MyFuture) fn foo() -> i32 {...}

try(MyResult) fn bar() -> i32 {...}

```

---

<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:** [May 18, 2018, 12:30pm UTC](https://internals.rust-lang.org/t/pre-rfc-flexible-try-fn/7564/10 "2018-05-18T12:30:17Z")

</div>

> [@DDOtten](#):
>
> This would create two different ways of doing things

This is true, but I also don't believe it will become a problem in practice. It is clear to me that given the choice between `fn + return Ok(x)` and `try fn + Ok(x)`, we should heavily lint in favor of `try fn` as the idiomatic choice. This eliminates the _"analysis paralysis"_ / _"decision fatigue"_.

> [@DDOtten](#):
>
> becoming more readable or more ergonomic

This is debatable. I think the winnings in terms of simple syntax for being generic over `Try` carriers is important.

Another major benefit, _from my perspective_ is that it removes the noise of `Ok` and `Err`, which is just _pure plumbing_ in your computation, and instead allows you to focus on your problem domain. The focus on the problem domain will also show in the code and thus make it more readable. This is fundamentally what monads are about, [they get rid of the plumbing](http://www.cse.chalmers.se/edu/course/TDA342_Advanced_Functional_Programming/lecture3.html). Since we Rust isn't a pure functional language, monads won't work well here, so we use something more tailored for Rust.

Furthermore, `try` scales better. It is just one annotation at one place; If you have many early return and failure paths, then it can become quite noisy.

Finally, I think this is a case of a major increase to readability globally. While you might not "save more than a few characters" at each point, `try fn` will (I predict) become so commonplace that the net win becomes quite large.

Here's an example using `try fn` and postfix macros to clean up some code from rfcbot real nicely:

```rust
impl Team {
    try fn validate(&self) -> DashResult<()> {
        use domain::schema::githubuser::dsl::*;
        let conn = &*(DB_POOL.get()?);

        for member_login in self.member_logins() {
            let test = githubuser.filter(login.eq(member_login))
                                 .first::<GitHubUser>(conn);
            test.unwrap_or! { err =>
                error!("unable to find {} in database: {:?}", member_login, why);
                throw err
            }
        }
    }
}

```

> [@DDOtten](#):
>
> This would also allow another thing before `fn` with would lead to things like `unsafe const async try fn` where it would be very hard to remember the order these things should go in.

This is not a problem. It is _easily_ solved by just allowing any permutation of `unsafe const async try`. In terms of BNF:

```rust
effect ::= "unsafe" | "const" | "try" | "async" ;
vis ::= "pub" | ... ;
fundecl ::= vis? effect* "fn" ... ;

```

To make code more uniform and readable, rustfmt will then normalize `unsafe const async try` into a standard form. But while writing code, it should not be a hindrance.

> [@DDOtten](#):
>
> To be honest I am against `Ok` wrapping in general because it reduces local reasoning and increases the complexity of the language just to save 4 characters, including the braces.

Would you similarly be fine with typing `function` instead of `fn`? The latter only saves 6 characters.

How does it reduce local reasoning and is fallibility-plumbing important for the reasoning? It is true that reasoning becomes function-local instead of expression local, but that hardly seems like a big problem if you don't write absurdly long functions (but then you have other reasoning problems on your hand...).

---

<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:** [May 18, 2018, 12:37pm UTC](https://internals.rust-lang.org/t/pre-rfc-flexible-try-fn/7564/11 "2018-05-18T12:37:41Z")

</div>

I just want to reiterate my position that `Ok`, `Err`, `Some` and `None` are not seen as “noise” by everyone. Personally, I find them to be important markers in code.

The rfcbot code is a good example. It took me a moment to see how and where it’s decided that things are valid. A trailing `Ok(())` is a simple marker communicating “everything is ok if the function makes it to the end.”

---

<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:** [May 18, 2018, 12:43pm UTC](https://internals.rust-lang.org/t/pre-rfc-flexible-try-fn/7564/12 "2018-05-18T12:43:08Z")

</div>

> [@phaylon](#):
>
> It took me a moment to see how and where it’s decided that things are valid

With `try fn`, the assumption is that if not stated otherwise, everything went OK.

I find this easier to reason about, and it is also the way you reason in many mainstream languages with exception handling (but we can also get the benefits of _errors as values_ and eat our 🍰 keep it...).

The moment this took you _could_ (you know yourself best of course...) also be a factor of being used to the current model of writing `Ok(..)`.

---

<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:** [May 18, 2018, 12:51pm UTC](https://internals.rust-lang.org/t/pre-rfc-flexible-try-fn/7564/13 "2018-05-18T12:51:03Z")

</div>

> [@Centril](#):
>
> With `try fn` , the assumption is that if not stated otherwise, everything went OK.

In my opinion putting the `Ok` at the point of decision (in other words: the end) is the superior signal. Especially since it's a signal that works everywhere. If a match arm decides success, there's `return Ok`. It works the same for functions, closures, blocks, assignments, function arguments, and all block or expression macros.

Similarly, in this coding style, the absence of `Ok`, `Err`, etc. means something else makes the decision.

---

<div class="post-metadata">

**Author:** ![newpavlov](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/newpavlov/32/3290_2.png) [@newpavlov](https://internals.rust-lang.org/u/newpavlov)\
**Post date:** [May 18, 2018, 1:01pm UTC](https://internals.rust-lang.org/t/pre-rfc-flexible-try-fn/7564/14 "2018-05-18T13:01:50Z")

</div>

Aside from somewhat subjective notion regarding noisiness of `Ok(())` (though I certainly will not miss it) and ability to focus on the problem at hand, another argument for `Ok` wrapping discussed in the @withoutboats’s “catching functions” thread is a shorter editing distance between fallible and infallible functions. Imagine this function:

```rust
fn foo() -> u64 {
    // N returns here
   let data = bar().unwrap();
   // M returns here
   if !check_stuff() { panic!("check failed") }
   // K returns here
}

```

Now we want to make this function fallible (e.g. we decided to remove `unwraps` after initial prototyping), today we’ll have to find all returns and do `Ok` wrapping manually. While with this proposal we’ll just write:

```rust
try fn foo() -> Result<u64, MyError> {
    // N returns here
   let data = bar()?;
   // M returns here
   // or Err(MyError("check failed"))? if we decide to drop `throw` keyword`
   if !check_stuff() { throw MyError("check failed"); }
   // K returns here
}

```

It’s clear that `try fn` allows much faster refactoring of the code in such cases. Arguably good IDE could help with such changes, but in my opinion it’s a bad argument.

---

<div class="post-metadata">

**Author:** ![broken-pen](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/broken-pen/32/13250_2.png) [@broken-pen](https://internals.rust-lang.org/u/broken-pen)\
**Post date:** [May 18, 2018, 1:11pm UTC](https://internals.rust-lang.org/t/pre-rfc-flexible-try-fn/7564/15 "2018-05-18T13:11:48Z")

</div>

What worries me somewhat about this proposal is that not only error types get converted automatically when returned via `throw`, but success types as well. Specifically, this example from the OP:

```rust
// converts `1` and `"ok"` into `Foo` automatically
try fn foo1() -> Foo {
    if true { return 1; }
    return "ok";
}

```

Because `From::from()` is a potentially expensive operation, I feel this goes too much against Rust’s tendencies to make such operations explicit. This is why we don’t automatically convert from `&str` to `String`, for example.

My (subjective) opinion is that at least in this example, I would prefer seeing the `.into()` on both returns, noisy as they may seem to others.

---

<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:** [May 18, 2018, 1:12pm UTC](https://internals.rust-lang.org/t/pre-rfc-flexible-try-fn/7564/16 "2018-05-18T13:12:49Z")

</div>

My arguments against the editing distance point would be:

- I’ll still have to update all call sites anyway.
- Having a review of the function is a good idea anyway when you introduce a new early return or add error handling. In your example not doing this might lead to a missed panic site.
- I’d consider writing convenience less important than clarity when reading.

---

<div class="post-metadata">

**Author:** ![newpavlov](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/newpavlov/32/3290_2.png) [@newpavlov](https://internals.rust-lang.org/u/newpavlov)\
**Post date:** [May 18, 2018, 1:22pm UTC](https://internals.rust-lang.org/t/pre-rfc-flexible-try-fn/7564/17 "2018-05-18T13:22:20Z")

</div>

> [@broken-pen](#):
>
> What worries me somewhat about this proposal is that not only error types get converted automatically when returned via `throw` , but success types as well.

I think you misunderstood the proposal a bit, in `Foo` example author will have to explicitly opt into such conversions by implementing `Try` traits for `Foo` as he sees fit, it will not be done automatically. For `Result` and `Option` there is no automatic conversion for `TryOk`, and `into()` is used only for errors, which is equivalent to that `?` currently does.

> [@phaylon](#):
>
> I’d consider writing convenience less important than clarity when reading.

My example was about an objective advantage of `try fn`, as for subjective I personally think that `try fn` will make reading and understanding code easier, not harder, because it will allow to focus on happy path, which usually contains the most important program logic. (i.e. I agree with @Centril 🙂 )

---

<div class="post-metadata">

**Author:** ![Ixrec](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ixrec/32/6754_2.png) [@Ixrec](https://internals.rust-lang.org/u/Ixrec)\
**Post date:** [May 18, 2018, 1:27pm UTC](https://internals.rust-lang.org/t/pre-rfc-flexible-try-fn/7564/18 "2018-05-18T13:27:35Z")

</div>

I’ve heard this “editing distance” argument before, but I’ve never seen a post that actually demonstrated it. Since you’ve left out the “do Ok wrapping manually” case and are hiding most of the snippets behind comments, I have no way of seeing that there’s a significant benefit here unless I’ve already been convinced that try functions are a win.

Could you flesh out your example so those of us who are not convinced can see what you’re seeing?

---

<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:** [May 18, 2018, 1:38pm UTC](https://internals.rust-lang.org/t/pre-rfc-flexible-try-fn/7564/19 "2018-05-18T13:38:23Z")

</div>

> [@newpavlov](#):
>
> My example was about an objective advantage of `try fn` , as for subjective I personally think that `try fn` will make reading and understanding code easier, not harder, because it will allow to focus on happy path, which usually contains the most important program logic.

Sure. I was just stating that that while having to write less is/can be a plus, when weighing it against the downsides it has for me, I'll always prefer to write out those `Ok`s, `Err`s and so on.

The "happy path" argument I believe also has its downsides. While you can often simply consider the happy path, once you start hiding the unhappy path it of course becomes harder to notice it. And the points where happy and unhappy paths diverge are the most important to me. I wouldn't want to hide the points where unhappiness gets involved when I'm mutating things, for example.

---

<div class="post-metadata">

**Author:** ![broken-pen](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/broken-pen/32/13250_2.png) [@broken-pen](https://internals.rust-lang.org/u/broken-pen)\
**Post date:** [May 18, 2018, 1:39pm UTC](https://internals.rust-lang.org/t/pre-rfc-flexible-try-fn/7564/20 "2018-05-18T13:39:25Z")

</div>

> [@newpavlov](#):
>
> I think you misunderstood the proposal a bit, in `Foo` example author will have to explicitly opt into such conversions by implementing `Try` traits for `Foo` as he sees fit, it will not be done automatically. For `Result` and `Option` there is no automatic conversion for `TryOk` , and `into()` is used only for errors, which is equivalent to that `?` currently does.

I see, thanks for the clarification!

[Next page](https://internals.rust-lang.org/t/pre-rfc-flexible-try-fn/7564.md?page=2)
