# 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:** 20\
**Page:** 3

<div class="post-metadata">

**Author:** ![H2CO3](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/h2co3/32/2849_2.png) [@H2CO3](https://internals.rust-lang.org/u/H2CO3)\
**Post date:** [May 14, 2018, 3:49pm UTC](https://internals.rust-lang.org/t/automatic-inside-try-blocks/7507/42 "2018-05-14T15:49:33Z")

</div>

Most of those just… aren’t, though.

How does `Drop` and especially `Deref` affect control flow? Drop is a special case in this regard anyway: the whole point of RAII is that 1. we intuitively _expect_ objects to be destroyed upon scope exit, and 2. we don’t want to manage memory manually, because _that_ leads to errors. So `Drop`'s automatic behavior actually prevents large classes of errors and is very easy to understand, because it’s expected. Furthermore, it really doesn’t _do_ anything at the higher semantic level. It merely cleans up _exactly_ when it is necessary (which is ensured by scopes, ownership, and dropck), and thus it can’t really lead to errors. This isn’t true of several (most) features proposed in this thread.

How does inference _affect_ types? It doesn’t, really… it just _deduces_ or _computes_ types when possible, but it doesn’t _change_ them.

`Copy` isn’t really potentially expensive as only trivially-memcpy-able types without heap allocation can ever be `Copy`, and usually they are very small. `Deref` isn’t allowed to be expensive, either. Either the documentation or the Rust book (I can’t remember which one, maybe both) says explicitly that `AsRef`, `Deref`, and similar conversions should only be implemented if the conversion is trivial or almost trivial, and that it must never involve expensive operations such as dynamic allocation or lots of copying.

---

<div class="post-metadata">

**Author:** ![SheepKey](https://avatars.discourse-cdn.com/v4/letter/s/e5b9ba/32.png) [@SheepKey](https://internals.rust-lang.org/u/SheepKey)\
**Post date:** [May 14, 2018, 4:07pm UTC](https://internals.rust-lang.org/t/automatic-inside-try-blocks/7507/43 "2018-05-14T16:07:18Z")

</div>

> Even tho I am not in favor of this particular proposal, it is not true that Rust forces everything to be explicit (c.f. type inference, default match bindings, etc.)

@H2CO3 did a great job explaining why the specific implicit things that exist in Rust are OK. Here is my clarification:

They are trivial to reason about. They do not have implications for performance or correctness or semantics.

Rust is a RAII language. It is expected that resources are managed through destructors (`Drop`), cleaned up automatically at the end of the scope. This is consistent behaviour with no exceptions. It is trivial to reason about (you know whatever is owned in your current scope will be destroyed at the end of the scope).

Type inference: again, trivial to reason about. If the compiler can easily infer the type from the context, so can you. The type of everything is obvious from the immediate context around it. This is precisely why inference is a good thing: having to type out obvious information is unnecessary clutter. It does not affect semantics or performance or anything else of importance in any way.

`Copy`, yes, while it does correspond to a runtime operation that is done implicitly, Rust guarantees that it will always be a single, simple `memcpy`. This means that it is incredibly cheap to do (modern CPUs are very fast at `memcpy`) and, again, trivial to reason about.

`Deref` and friends: they are specifically intended only for cheap and trivial, obvious conversions. Same things apply.

Same thing with autoreferencing for `match`.

Contrast all of this with proposals like implicit `?` or implicit `await`. Both of these hide important information.

Implicit `?` silently converts a type to another one. This is dangerous. It also means that it is no longer obvious what operations can fail. You have to know the signature of the function you are calling, which often requires looking up documentation. This is _not_ trivial to reason about. It also introduces the possibility of an early return, which means that subsequent code will not execute if a fallible operation fails, and this _not_ being obvious from the code is a _very bad thing_ that can lead to unexpected surprises.

Implicit `await` hides the semantics of `async` functions. You cannot know how a given code calling a given function will behave, without consulting the signature of the called function. It makes reasoning about code non-trivial.

This is really my big objection. Any implicit thing in the language should only be something that is truly obvious from looking _only_ at the immediate context where it is written, and trivial to reason about.

> Please tone down the all-caps, etc.

Done 🙂. I feel strongly about this issue and my previous post was maybe a little too-ranty.

@rpjohnst

> We already have quite a few “implicit” things that affect control flow (panics, Drop, Deref), data types (inference, coercions, default binding modes), and potentially-expensive operations (Copy, Try conversions, also Deref).

> You even call some of these out, but you don’t really justify why they’re okay while try/async would not be. There’s been quite extensive discussion here, more blanket “DO NOT” declarations do not really help advance that discussion.

Done. Addressed and clarified my views in detail. Hopefully this new post of mine advances the discussion in a more productive way 🙂.

---

<div class="post-metadata">

**Author:** ![gbutler](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/gbutler/32/3670_2.png) [@gbutler](https://internals.rust-lang.org/u/gbutler)\
**Post date:** [May 14, 2018, 4:10pm UTC](https://internals.rust-lang.org/t/automatic-inside-try-blocks/7507/44 "2018-05-14T16:10:52Z")

</div>

> [@SheepKey](#):
>
> Any implicit thing in the language should only be something that is truly obvious from looking _only_ at the immediate context where it is written, and trivial to reason about.

Couldn't agree more!

---

<div class="post-metadata">

**Author:** ![H2CO3](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/h2co3/32/2849_2.png) [@H2CO3](https://internals.rust-lang.org/u/H2CO3)\
**Post date:** [May 14, 2018, 4:14pm UTC](https://internals.rust-lang.org/t/automatic-inside-try-blocks/7507/45 "2018-05-14T16:14:03Z")

</div>

[Edit: looks like @SheepKey already made some of the arguments in this reply in the meantime. Anyway, I'm keeping it here for reference.]

Oh, one more thing, which I'm not sure I explained well enough.

> [@rpjohnst](#):
>
> Perhaps we need another reminder that [“explicit” is not a helpful criterion](https://boats.gitlab.io/blog/post/2017-12-27-things-explicit-is-not/), and that [its usefulness is quite context-dependent](https://blog.rust-lang.org/2017/03/02/lang-ergonomics.html).

I do agree with this _to some extent._ I do think "explicit" _is_ a helpful criterion though: it's very clear what it means. I also think there are several important cases where implicit is better than explicit, including type inference and RAII. I would also argue, however, that _typically_ explicitness helps avoid confusion, since in the majority of the cases, when we write down some code, we are actively doing something with said code, or we are expecting it to actively do/affect/change something.

Incidentally, in the bigger picture, this is _exactly_ why RAII and type inference shine as the prime example of good implicitness: they are helping us avoid noise or redundancy when we do know what is supposed **and bound** to happen anyway. Inferred types are guaranteed to be type-safe and consistent; RAII-based memory management ("ownership") is also guaranteed to be correct, to the extent that it is one of the most important pillars of Rust's memory safety model.

However, many other "convenience"-oriented proposals fail to make the distinction between language features and constructs that merely help avoid redundancy versus those that hide something bearing a semantically-important side effect. Early return from a scope is one such effect, since it affects control flow, consequently the exact operations which will be executed. This is why hiding such an early return can be a source of confusion and bugs.

---

<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 14, 2018, 4:40pm UTC](https://internals.rust-lang.org/t/automatic-inside-try-blocks/7507/46 "2018-05-14T16:40:50Z")

</div>

> [@SheepKey](#):
>
> Implicit `?` silently converts a type to another one. This is dangerous. It also means that it is no longer obvious what operations can fail. You have to know the signature of the function you are calling, which often requires looking up documentation. This is _not_ trivial to reason about. It also introduces the possibility of an early return, which means that subsequent code will not execute if a fallible operation fails, and this _not_ being obvious from the code is a _very bad thing_ that can lead to unexpected surprises.

I certainly agree that early-exit is something to be wary about- I've said so several times in this thread. But that doesn't make it non-trivial- it only makes it non-local, and only in a very simple and straightforward way. And again, we have _plenty_ of non-local things, all of which you seem to be fine with...

So the real question is why the downsides of non-locality are fine in cases like RAII or panics or asserts, but not in the case of calling a fallible function, _especially_ in the face of potential benefits like `try`-polymorphism. (To be perfectly clear: I do think we probably should keep `?`. Just not that "_waves hands_ explicit _waves hands_" is a great reason to do so.)

> [@SheepKey](#):
>
> Implicit `await` hides the semantics of `async` functions. You cannot know how a given code calling a given function will behave, without consulting the signature of the called function. It makes reasoning about code non-trivial.

Ah, but in a different sense this is actually backwards. Under explicit await, you must consult the signature of the called function `foo()` to know whether it will run its fully body (the usual case) or do nothing until you await it (the `async` case). Under explicit async, you always know that `foo()` will run its full body regardless of its signature.

The explicit async thread discussed this at length, but it's not at all clear that knowing the locations of the suspension points is actually that important. Any function call, whether synchronous or asynchronous, can run nondeterministic code that affects shared state. The non-locality of "does this function call run its body" is quite possibly _more_ confusing than the non-locality of "might this function call suspend," especially given the Dart designers' experience.

So again, the real question is why "suspension point locality" is more important than "deferred execution locality." (Again, I recognize that people want suspension point locality, I just want the conversation to move beyond that and into why they want it _more_ than the alternatives.)

---

<div class="post-metadata">

**Author:** ![SheepKey](https://avatars.discourse-cdn.com/v4/letter/s/e5b9ba/32.png) [@SheepKey](https://internals.rust-lang.org/u/SheepKey)\
**Post date:** [May 14, 2018, 5:02pm UTC](https://internals.rust-lang.org/t/automatic-inside-try-blocks/7507/47 "2018-05-14T17:02:44Z")

</div>

Ok, thank you for furthering the discussion. You are making some good points.

> So the real question is why the downsides of non-locality are fine in cases like RAII or panics or asserts

RAII: I explained my view. Rust is fundamentally a RAII language. It is part of the ownership model and the fundamental way that resources are managed. It is universally expected throughout all Rust code. It is never surprising and always trivial to reason about.

Unlike RAII, which is consistent and expected everywhere, implicit `?` makes the semantics inconsistent and confusing.

Panics and asserts: these are intended as a way to catch bugs. They should only happen on catastrophic failure where the most sensible thing to do is abort the program, because a bug has been hit (like some invariant being violated) and it is unclear how the program could proceed from there. They should not occur as part of the normal execution of a program. This justifies their non-locality. They are a way for the program to commit suicide in a controlled way, in situations where there is nothing better that can be done. At least that is the intention; of course these features can be misused in various ways, but that is what conventions are for.

> To be perfectly clear: I do think we probably should keep ?. ... ...

Yeah, I understand you :). It is great to argue for the opposite side from your personal beliefs. It helps consider all sides better and see different arguments.

> especially in the face of potential benefits like try-polymorphism.

In the name of considering arguments for the opposite side ... I feel like I haven't considered the benefits of implicit `?` well enough. It seemed like such a clear-cut no-no. I will look at try-polymorphism in more detail and educate myself. Right now I don't have any valuable comments on it.

> I certainly agree that early-exit is something to be wary about- I’ve said so several times in this thread. But that doesn’t make it non-trivial- it only makes it non-local, and only in a very simple and straightforward way.

Silently converting types and hiding things that can fail are also big problems. So far, we have seen at least 3 major problems with the implicit `?` proposal. I feel like that is too much. Individually, these considerations might be fairly "trivial", but together, they introduce a lot of things that you have to be careful about. Since Rust's philosophy is to enable fearless programming without footguns/pitfalls as much as possible, anything like this that introduces such extra reasoning overhead goes against Rust's goals. I don't want to write in a language where I have to constantly worry about missing something that could go wrong. If I did, I'd be writing C/C++. This is possibly the single main reason why I love Rust and I'd hate it if new features were introduced that go against that. I love that Rust makes everything I need to consider about the correctness of my code obvious from the syntax and semantics of the language and enforces that I deal with all of it.

> implicit await/async stuff

OK, I will admit that I perhaps should not have commented on this. I have almost no experience with writing async code and there are many people in this community with far more valid opinions, based on actual experience, to drive those discussions and make decisions about the best trade-offs. I don't really understand the implications. Now I feel like my view was misled, as I did not realise the 2-sided nature of the tradeoffs involved.

However, your post was insightful. Thank you! I learned new things. 🙂

---

<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 14, 2018, 5:36pm UTC](https://internals.rust-lang.org/t/automatic-inside-try-blocks/7507/48 "2018-05-14T17:36:34Z")

</div>

> [@SheepKey](#):
>
> Type inference: again, trivial to reason about.

Honestly; I've often found that type inference is anything but trivial to reason about in some cases. Sure, you could write out the types if you wanted to; but when a whole lot of things are being inferred together and when I am writing something in a generic context, I have to rely on really good naming of functions for the semantics to be clear enough.

I don't think it is as easy as you portray things to be.

---

<div class="post-metadata">

**Author:** ![SheepKey](https://avatars.discourse-cdn.com/v4/letter/s/e5b9ba/32.png) [@SheepKey](https://internals.rust-lang.org/u/SheepKey)\
**Post date:** [May 14, 2018, 7:06pm UTC](https://internals.rust-lang.org/t/automatic-inside-try-blocks/7507/49 "2018-05-14T19:06:31Z")

</div>

Fair enough. I guess people’s experiences vary and im biased towards my experiences.

I tend to follow the intention rather than the technicalities.

The intention behind type inference is to make code clearer when the types are obvious, allowing you to omit redundant information. That’s how I use it. If the types are obvious to me (and it feels redundant to write them down) and the compiler can infer them, I will omit them. If the code feels clearer to read with them written in, even if the compiler can infer them, I will write them out.

Yeah, I can see how someone who has different habits from me would have a different experience. If you don’t actively think about what is most clear and readable, but rather you always omit types unless the compiler complains and only add them in to make the code compile, then yeah I can see how you would be omitting types in many confusing places.

This brings up a great point that I don’t often see discussed enough. People usually tend to argue about new features mostly on technical merits. It would be great to also give more consideration to how those features fit with different people’s coding mindset and habits.

Edit: more clear examples (things that should be given some thought when evaluating a new feature):

- how would a lazy person who just writes the minimal code to get things to work use the feature?
- how would it affect the experience for a person who likes to copypaste code examples (from books/tutorials/stackoverflow/etc) and hack them until they work?
- how would it be used by a perfectionist who focuses on the pure elegance of their code?
- many others that i am missing

---

<div class="post-metadata">

**Author:** ![MajorBreakfast](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/majorbreakfast/32/4015_2.png) [@MajorBreakfast](https://internals.rust-lang.org/u/MajorBreakfast)\
**Post date:** [May 14, 2018, 7:11pm UTC](https://internals.rust-lang.org/t/automatic-inside-try-blocks/7507/50 "2018-05-14T19:11:53Z")

</div>

> [@Centril](#):
>
> I have to rely on really good naming of functions for the semantics to be clear enough.

Or well named variables. Let's not forget that we often read code that others have written. We know that it works. We just need to be able to follow what's happening. Type inference helps with keeping the "noise" down, so that we can see what the code is doing. Yes we're hiding information. But, it's a trade-off that I'd make any day.

Edit: And let's not forget that Rust forces us to spell out function signatures. Type inference mostly only hides redundant stuff.

---

<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 14, 2018, 7:15pm UTC](https://internals.rust-lang.org/t/automatic-inside-try-blocks/7507/51 "2018-05-14T19:15:09Z")

</div>

> [@SheepKey](#):
>
> This brings up a great point that I don’t often see discussed enough. People usually tend to argue about new features mostly on technical merits. It would be great to also give more consideration to how those features fit with different people’s coding mindset and habits.

Oh this happens all the time. The reason why technical arguments might seem more prominent is that technical arguments are more objective, and once raised tend to be impossible to disagree with. Arguments based on a particular "coding mindset" tend to be not only subjective, but impossible to form a consensus on. Other people have a different mindset, neither is "right" or "wrong", there aren't any arguments that would make someone "change sides", and there's no way to acquire convincing evidence that either is so much more popular that it should dictate a feature's design. (e.g., I think there's a lot of this going on with try/throw/catch discussions recently)

But more useful non-technical questions like:

> [@SheepKey](#):
>
> - how would a lazy person who just writes the minimal code to get things to work use the feature?
> - how would it affect the experience for a person who likes to copypaste code examples (from books/tutorials/stackoverflow/etc) and hack them until they work?
> - how would it be used by a perfectionist who focuses on the pure elegance of their code?

do get raised in RFC discussions all the time, when the subject is broad enough for this to matter. If you look at some of the module reform RFCs and internals threads from last year you'll see dozens upon dozens of arguments getting made based on exactly these questions, some of which became major design goals in the final proposal (e.g., preventing "path confusion", where paths that are valid in the root module are invalid in any other module, because that specific inconsistency was a tremendous stumbling block for... well not even just newbies, it confused everyone).

---

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

</div>

> [@gbutler](#):
>
> I believe this would just be BAD™. As I previously argued in other threads, I felt it a mistake for Rust to adopt try/catch terminology for it’s error handling as it would encourage endless bike-shedding on making it work more like traditional try…catch…finally in other languages. This thread seems to be an example of that. Hard Down-Vote.

Maybe. I feel like there was always going to be bikeshedding on it. However, I think the design decision more immediately responsible for this suggestion is renaming `catch { ... }` to `try { ... }`. The motivation here was that `try { try_something()? }` seems redundant:

> [@ibkevg](#):
>
> In the case of code within try{…} blocks, I wondered why the need for ? was retained because it seems redundant and a bit of a wart left behind from the process of evolution.

And there is actually a point here. The reason people wanted `catch` renamed to `try` was because, in languages with `try { ... } catch { ... }`, the fallible code goes in the `try` block, so if you think of `try/catch { ... }` as a block with fallible code in it, it makes more sense to call it '`try`'. However, this is based on a superficial parallel! In languages with `try { ... } catch { ... }`, `try { ... }` on its own (if it's permitted) _doesn't actually catch errors_; it serves solely to mark code that can fail, _the role served by `?` in Rust_. So of course someone would come along later and think that `try { try_something()? }` is redundant. By naming it `try { ... }`, we've hidden the fact that it's actually a `catch` operation—completely orthogonal to `?`—and given it a name which suggests it does the same thing as `?`.

---

<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 14, 2018, 7:20pm UTC](https://internals.rust-lang.org/t/automatic-inside-try-blocks/7507/53 "2018-05-14T19:20:54Z")

</div>

> [@steven099](#):
>
> The reason people wanted `catch` renamed to `try` was because, in languages with `try { ... } catch { ... }` , the fallible code goes in the `try` block

Eh, no, that's not the only reason, or even the main reason. In fact I think it'd be doing all sides of the debate a disservice to claim there is any single main reason, so I'm just going to link the comment where @scottmcm summarized _all_ the arguments (afaik no new arguments have surfaced in the past month): [RFC: Reserve `try` for `try { .. }` block expressions by Centril · Pull Request #2388 · rust-lang/rfcs · GitHub](https://github.com/rust-lang/rfcs/pull/2388#issuecomment-381059548)

---

<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:** [May 14, 2018, 7:26pm UTC](https://internals.rust-lang.org/t/automatic-inside-try-blocks/7507/54 "2018-05-14T19:26:25Z")

</div>

> [@Ixrec](#):
>
> Eh, no, that’s not the only reason, or even the main reason. In fact I think it’d be doing all sides of the debate a disservice to claim there is any single main reason, so I’m just going to link the comment where @scottmcm summaries _all_ the arguments (which I’m pretty sure have not changed in the past month)

This point:

> It allows us to leverage peoples' intuitions from other languages

which is the most developed, mostly deals with exactly what I was talking about: mapping the Rust feature to `try { ... }` blocks in other languages as the basis for people to form intuitions. And I'm pointing out here that this is a case where that intuition is misleading, which I think challenges the assertion that people's intuitions about `try { ... }` are more useful than they would be for `catch { ... }`.

Edit: It could turn out on balance that `try { ... }` does encourage better intuitions. However, reasoning about what intuitions people will form is hard, and finding evidence to support that reasoning can be even harder. I think this thread is interesting just because its an actual tangible piece of evidence on the question. Obviously, you can't extrapolate from one data point, and getting evidence in support of `try { ... }` is going to be harder now that people won't be trying to form an intuition about `catch { ... }`. You could argue that the reason people pushed for `try { ... }` in the first place was because they weren't getting the right intuition for `catch`, but this is iffy because you could also say that this is a preference formed _after_ reaching a correct intuition based on `catch` which has no bearing on whether one syntax is more intuitive than the other.

---

<div class="post-metadata">

**Author:** ![SheepKey](https://avatars.discourse-cdn.com/v4/letter/s/e5b9ba/32.png) [@SheepKey](https://internals.rust-lang.org/u/SheepKey)\
**Post date:** [May 14, 2018, 7:27pm UTC](https://internals.rust-lang.org/t/automatic-inside-try-blocks/7507/55 "2018-05-14T19:27:28Z")

</div>

OK, it is great that is being discussed!

I guess the fault is with me for not following those discussions 😃 , which gave me that impression.

Many RFC discussions tend to get really really long and I don’t have the time or the attention span to read the whole thing. Also most of the info near the beginning of the thread quickly becomes irrelevant as it gets shot down later in the discussion. There is no easy way to start reading, since you don’t know if the information early on is important or not until you read the replies later on (which you can’t always understand if you haven’t read the earlier info, so a circular dependency 😃 ).

It would be great if these discussions could somehow be made more accessible to people who haven’t been there from the beginning, without reading the whole thing. Perhaps with periodic “checkpoint posts” that summarise and reiterate the state of the discussion, so that one could start reading from there onwards and ignore everything prior? I’ve seen a few of the recent big discussions (async/await library support, `try` blocks) have at least one “checkpoint post” like this and I think it is good practice! It should happen more!

That said, this got quite off-topic at this point. (but then, this whole thread seems to be very off-topic at this stage…)

---

<div class="post-metadata">

**Author:** ![MajorBreakfast](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/majorbreakfast/32/4015_2.png) [@MajorBreakfast](https://internals.rust-lang.org/u/MajorBreakfast)\
**Post date:** [May 14, 2018, 7:35pm UTC](https://internals.rust-lang.org/t/automatic-inside-try-blocks/7507/56 "2018-05-14T19:35:03Z")

</div>

> [@SheepKey](#):
>
> It would be great if these discussions could somehow be made more accessible to people who haven’t been there from the beginning, without reading the whole thing

@aturon did something like that in the [async/await RFC](https://github.com/rust-lang/rfcs/pull/2394): He marked comments as "outdated" after they became irrelevant.

* * *

Edit: I really like the renaming to "try". The fallible code goes into the `try` block - just like in most other programming languages. Makes sense to me.

---

<div class="post-metadata">

**Author:** ![SheepKey](https://avatars.discourse-cdn.com/v4/letter/s/e5b9ba/32.png) [@SheepKey](https://internals.rust-lang.org/u/SheepKey)\
**Post date:** [May 14, 2018, 7:37pm UTC](https://internals.rust-lang.org/t/automatic-inside-try-blocks/7507/57 "2018-05-14T19:37:26Z")

</div>

Yeah that is another great thing to do!

I just wanted to share that I really appreciate such efforts and encourage it to happen more! It really helps.

---

<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 14, 2018, 7:47pm UTC](https://internals.rust-lang.org/t/automatic-inside-try-blocks/7507/58 "2018-05-14T19:47:27Z")

</div>

> [@MajorBreakfast](#):
>
> Edit: And let’s not forget that Rust forces us to spell out function signatures. Type inference mostly only hides redundant stuff.

Right. With function-local inference (what Rust has), the degree to which type inference is legible is proportional (to some extent) to the length of a function. The longer it is, the more it will start to feel like global type inference (which Haskell has, but Rust doesn't).

In Haskell, I typically use global type inference as a development tool where 1) I define a function (without type signature, unless I'm sure of what it will be...), 2) ask the REPL what the type of the function is, 3) take the type from the REPL and paste it as the signature, 4) start over at 1). I only keep one function globally inferred at a time. All functions I commit to VCS have their type signatures there explicitly. I also tend to write very small functions.

> [@MajorBreakfast](#):
>
> Or well named variables.

As a serial eta-reducer (who likes the point-free, or "point-less" according to some, style), I try to avoid let bindings 😉

---

<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:** [May 14, 2018, 7:55pm UTC](https://internals.rust-lang.org/t/automatic-inside-try-blocks/7507/59 "2018-05-14T19:55:41Z")

</div>

> [@MajorBreakfast](#):
>
> Edit: I really like the renaming to “try”. The fallible code goes into the `try` block

...or outside the `try` block. The only consistent marker of where fallible code can be is `?`. The only thing `try { ... }` is doing here is preventing errors from propagating to the function boundary, something that `try { ... }` doesn't do on its own in other languages.

Anyways, I can understand why people who already understand the feature might prefer '`try`', I'm just not sure if this preference has any bearing on the relative intuitiveness of the two choices. I guess we'll find out based on how often people think that `try` makes `?` redundant.

---

<div class="post-metadata">

**Author:** ![gbutler](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/gbutler/32/3670_2.png) [@gbutler](https://internals.rust-lang.org/u/gbutler)\
**Post date:** [May 14, 2018, 8:05pm UTC](https://internals.rust-lang.org/t/automatic-inside-try-blocks/7507/60 "2018-05-14T20:05:06Z")

</div>

> [@steven099](#):
>
> I guess we’ll find out based on how often people think that `try` makes `?` redundant.

My prediction is that it will be endlessly brought up by people new to the language. They will constantly wonder why "try { ... }" doesn't work like other language and they will constant insist that Rust has a broken/deficient implementation of exception handling and try...catch...finally (instead of understanding what Rust error handling really is) and constantly insist that it needs to be fixed in the next edition.

---

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

</div>

To be fair, the only way to avoid this _completely_ might be to have try…catch… ~~finally~~ 😉. If the goal is not to have try…catch… ~~finally~~ because we think Rust can offer a better model, then this might just be an inevitability.

Edit: See below.

[Previous page](https://internals.rust-lang.org/t/automatic-inside-try-blocks/7507.md?page=2)

[Next page](https://internals.rust-lang.org/t/automatic-inside-try-blocks/7507.md?page=4)
