# Adding a third error-handling type for when no added context is needed

**URL:** <https://internals.rust-lang.org/t/adding-a-third-error-handling-type-for-when-no-added-context-is-needed/19722>\
**Category:** language design\
**Created:** [October 16, 2023, 10:19pm UTC](https://internals.rust-lang.org/t/adding-a-third-error-handling-type-for-when-no-added-context-is-needed/19722 "2023-10-16T22:19:25Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![LThoerner](https://avatars.discourse-cdn.com/v4/letter/l/47e85d/32.png) [@LThoerner](https://internals.rust-lang.org/u/LThoerner)\
**Post date:** [October 16, 2023, 10:19pm UTC](https://internals.rust-lang.org/t/adding-a-third-error-handling-type-for-when-no-added-context-is-needed/19722/1 "2023-10-16T22:19:25Z")

</div>

## The Problem

Throughout my ~1 year of programming in Rust, I have semi-frequently found myself in a situation where I need to know whether a function that would otherwise return nothing/`()` succeeded or failed, but not _why_ it succeeded or failed. I could do this one of four obvious ways without using any external crates.

1. I could use a `bool`, using `true` to indicate success and `false` to indicate failure.
2. I could use `Option<()>`, using `Some(())` to indicate success and `None` to indicate failure.
3. I could use `Result<(), ()>`, using `Ok(())` to indicate success and `Err(())` to indicate failure.
4. I could use a custom enum, using a `Success` and `Failure` variant. I do not think any of these solutions are sufficient. I have listed my reasoning for disliking each of these methods below (in their respective order).
5. `bool`s do not carry the requisite semantic meaning, making my code much less-readable.
6. `Option<()>` is somewhat of an antipattern and communicates the wrong semantic meaning. "There could be some nothing, or nothing here" is basically nonsensical.
7. `Result<(), ()>` is also an antipattern in my opinion, as `Result`s are explicitly meant to be used for enumerated error types, except in the case of `Infallible`. In addition to this, it prevents you from using `?` for `Option<T>` returns, or for a `Result` type with different generic parameters (which is pretty much all of them).
8. Custom enums lack standardization if I were to expose this type in a public interface, and they also prevent me from using the `?` operator entirely.

## The Solution

I think that `std` should implement the following type (names are tentative):

```rs
enum Status {
    Success,
    Failure,
}

```

The reason why I think that this should be in `std`, and not just some 3rd-party crate, is that it would allow Rustc to support the `?` operator as a lossy conversion for both `Option<T>` and `Result<T, E>` in a function which returns `Status`. Without implementation into the language, the only way I could see this being possible is by using procedural macros to tag functions, which tends to have a major negative impact on compile times, and can often cause problems with Cargo check/RA/Cargo clippy.

## Why?

1. Enumerated error types are great, but they are not always necessary.
2. Some errors cannot accurately be classified, or at least not usefully. This is especially the case when it comes to interacting with external systems and certain FFI systems.
3. The current non-enumerated error type does not have the correct semantic meaning to be used for this problem.
4. Some crates end up using something like `anyhow` because their error types are not easily-enumerable, and in some of these cases it's because the crate is basic and the developer does not feel that their users will have any need for robust error types. Though it is generally discouraged for crates to lack error handling in this way, it seems like something of a "harm reduction" (sorry for the loaded term here) method to prevent careless crate developers from forcing their consumers to use `anyhow`.
5. Not every crate is a library. Binary developers should have better flexibility as to how they handle errors, as it is not their responsibility to provide a good interface to other programmers - only to themselves and their teams.
6. This would help to break the tendency of `Option<T>` and `Result<T, E>` types to be close to mutually-exclusive in a project due to poor ergonomics. Though it's hard to communicate this feeling exactly, I suspect that most readers will understand what I mean.
7. Though I would say this tentatively at best, as someone who has never contributed to `std`, this might be a way to provide an obvious error return for functions such as `Vec::insert()` for which reasonable and common error cases will cause a panic. This is based on my understanding that one of the main reasons that a panic is used in place of a `Result` is due to ergonomic concerns. I may be completely incorrect in this regard, so feel free to correct me.

I am happy to hear your feedback on this, please let me know if you have any questions.

---

<div class="post-metadata">

**Author:** ![toc](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/toc/32/6692_2.png) [@toc](https://internals.rust-lang.org/u/toc)\
**Post date:** [October 16, 2023, 10:22pm UTC](https://internals.rust-lang.org/t/adding-a-third-error-handling-type-for-when-no-added-context-is-needed/19722/2 "2023-10-16T22:22:31Z")

</div>

This is actually quite similar to [ExitCode](https://doc.rust-lang.org/std/process/struct.ExitCode.html), although that has whole-process connotations that you maybe don't care about. Perhaps you could provide a couple motivating examples, and expand upon why this particularly needs to be in `std`, and can't be locally defined or at least in its own crate.

---

<div class="post-metadata">

**Author:** ![LThoerner](https://avatars.discourse-cdn.com/v4/letter/l/47e85d/32.png) [@LThoerner](https://internals.rust-lang.org/u/LThoerner)\
**Post date:** [October 16, 2023, 10:27pm UTC](https://internals.rust-lang.org/t/adding-a-third-error-handling-type-for-when-no-added-context-is-needed/19722/3 "2023-10-16T22:27:42Z")

</div>

I agree, unfortunately (as you mentioned) it carries too much baggage related to processes, and additionally would still lack support for the `?` operator in conversions.

---

<div class="post-metadata">

**Author:** ![quinedot](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/quinedot/32/7294_2.png) [@quinedot](https://internals.rust-lang.org/u/quinedot)\
**Post date:** [October 16, 2023, 10:56pm UTC](https://internals.rust-lang.org/t/adding-a-third-error-handling-type-for-when-no-added-context-is-needed/19722/4 "2023-10-16T22:56:37Z")

</div>

> [@LThoerner](#):
>
> `Result<(), ()>` is also an antipattern in my opinion, as `Result`s are explicitly meant to be used for enumerated error types, except in the case of `Infallible`.

Where is this written? `std` has non-`enum`, non-`Infallible` error types, for example.

> [@LThoerner](#):
>
> In addition to this, it prevents you from using `?` for `Option<T>` returns, or for a `Result` type with different generic parameters (which is pretty much all of them).

What exactly are you proposing? There's no more error data in your proposed type than in a `Result<_, ()>`.

---

<div class="post-metadata">

**Author:** ![LThoerner](https://avatars.discourse-cdn.com/v4/letter/l/47e85d/32.png) [@LThoerner](https://internals.rust-lang.org/u/LThoerner)\
**Post date:** [October 16, 2023, 11:04pm UTC](https://internals.rust-lang.org/t/adding-a-third-error-handling-type-for-when-no-added-context-is-needed/19722/5 "2023-10-16T23:04:27Z")

</div>

> [@quinedot](#):
>
> Where is this written? `std` has non-`enum`, non-`Infallible` error types, for example.

I did not mean by "enumerated" that it must be an `enum`, only that it must have some way of representing variants, which is often done with a struct that stores a variant enum in a `kind` field.

> [@quinedot](#):
>
> What exactly are you proposing? There's no more error data in your proposed type than in a `Result<_, ()>`.

I'm not sure exactly what you mean by this. My point was that the `Status` enum would be removing any of the data carried by the `Result`.

---

<div class="post-metadata">

**Author:** ![toc](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/toc/32/6692_2.png) [@toc](https://internals.rust-lang.org/u/toc)\
**Post date:** [October 16, 2023, 11:07pm UTC](https://internals.rust-lang.org/t/adding-a-third-error-handling-type-for-when-no-added-context-is-needed/19722/6 "2023-10-16T23:07:59Z")

</div>

Perhaps you could provide a couple motivating examples, and expand upon why this particularly needs to be in `std`, and can't be locally defined or at least in its own crate.

---

<div class="post-metadata">

**Author:** ![quinedot](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/quinedot/32/7294_2.png) [@quinedot](https://internals.rust-lang.org/u/quinedot)\
**Post date:** [October 16, 2023, 11:27pm UTC](https://internals.rust-lang.org/t/adding-a-third-error-handling-type-for-when-no-added-context-is-needed/19722/7 "2023-10-16T23:27:54Z")

</div>

> [@LThoerner](#):
>
> I'm not sure exactly what you mean by this.

Show the `Try` and related implementations and demonstrate how it improves the stated scenarios.

---

<div class="post-metadata">

**Author:** ![geeklint](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/geeklint/32/8671_2.png) [@geeklint](https://internals.rust-lang.org/u/geeklint)\
**Post date:** [October 16, 2023, 11:31pm UTC](https://internals.rust-lang.org/t/adding-a-third-error-handling-type-for-when-no-added-context-is-needed/19722/8 "2023-10-16T23:31:28Z")

</div>

I would probably use a unit struct (precedence: [std::fmt::Error](https://doc.rust-lang.org/std/fmt/struct.Error.html) ) and `Result<(), MyOperationFailure>`.

---

<div class="post-metadata">

**Author:** ![cg909](https://avatars.discourse-cdn.com/v4/letter/c/90ced4/32.png) [@cg909](https://internals.rust-lang.org/u/cg909)\
**Post date:** [October 17, 2023, 12:30am UTC](https://internals.rust-lang.org/t/adding-a-third-error-handling-type-for-when-no-added-context-is-needed/19722/9 "2023-10-17T00:30:56Z")

</div>

I'd also use a unit struct with `Result<(), MyOperationFailure>`.

Other precedents: [std::sync::mpsc::RecvError](https://doc.rust-lang.org/std/sync/mpsc/struct.RecvError.html), [std::​thread::AccessError](https://doc.rust-lang.org/std/thread/struct.AccessError.html) and [std::alloc::AllocError](https://doc.rust-lang.org/std/alloc/struct.AllocError.html).

> [@LThoerner](#):
>
> `Result<(), ()>` is also an antipattern in my opinion, […]. In addition to this, it prevents you from using `?` for `Option<T>` returns, or for a `Result` type with different generic parameters (which is pretty much all of them).

The custom unit struct has the advantage over `Result<(), ()>` that you can implement `From<MyOperationFailure>` for other error types to make using `?` easier.

Also, for any `Result<_, _>` you can write `fn_returning_result().ok()?` to use it for `Option<T>` returns.

If it makes your code easier to read for you, you can then emulate your proposed `enum Status` with

```rust
type Status = Result<(), MyOperationFailure>;
const SUCCESS: Status = Ok(());
const FAILURE: Status = Err(MyOperationFailure {});

```

without any additions to the standard library and without restricting the use of `?` for consumers.

---

<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:** [October 17, 2023, 2:54am UTC](https://internals.rust-lang.org/t/adding-a-third-error-handling-type-for-when-no-added-context-is-needed/19722/10 "2023-10-17T02:54:34Z")

</div>

If [the `Try` trait](https://doc.rust-lang.org/nightly/std/ops/trait.Try.html) is ever stable, you will be able to make your own result-like types.

BTW, [`ControlFlow`](https://doc.rust-lang.org/stable/std/ops/enum.ControlFlow.html) is the third `Try` type already.

---

<div class="post-metadata">

**Author:** ![Mokuz](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/mokuz/32/7225_2.png) [@Mokuz](https://internals.rust-lang.org/u/Mokuz)\
**Post date:** [October 17, 2023, 11:42am UTC](https://internals.rust-lang.org/t/adding-a-third-error-handling-type-for-when-no-added-context-is-needed/19722/11 "2023-10-17T11:42:49Z")

</div>

I sometimes wish `()` implemented `Try` because then we wouldn't need both `for_each` and `try_for_each` a single function would suffice because

```rust
foo.iter().try_for_each(|a| {
    a.baz(); // implicit `()`
}

```

and

```rust
foo.iter().for_each(|a| {
    a.baz();
}

```

would be identical.

second is being able to use `Try` on an `Option` in a function which returns `()`

---

<div class="post-metadata">

**Author:** ![SkiFire13](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/skifire13/32/7579_2.png) [@SkiFire13](https://internals.rust-lang.org/u/SkiFire13)\
**Post date:** [October 17, 2023, 1:29pm UTC](https://internals.rust-lang.org/t/adding-a-third-error-handling-type-for-when-no-added-context-is-needed/19722/12 "2023-10-17T13:29:06Z")

</div>

> [@Mokuz](#):
>
> I sometimes wish `()` implemented `Try` because then we wouldn't need both `for_each` and `try_for_each` a single function would suffice because

I think it's a bit too late for this, `for_each` has been stable for a long time and is not going away. There's also an argument to be made that some iterators may be able to implement `for_each` in a faster way due to not having to support early exit.

> [@Mokuz](#):
>
> second is being able to use `Try` on an `Option` in a function which returns `()`

For this `()` doesn't need to implement `Try`, it only needs `FromResidual<Option<Infallible>>`.

---

<div class="post-metadata">

**Author:** ![Mokuz](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/mokuz/32/7225_2.png) [@Mokuz](https://internals.rust-lang.org/u/Mokuz)\
**Post date:** [October 17, 2023, 3:19pm UTC](https://internals.rust-lang.org/t/adding-a-third-error-handling-type-for-when-no-added-context-is-needed/19722/13 "2023-10-17T15:19:31Z")

</div>

Point 1 I was thinking `try_*` could go away, but I agree it's probably more work than it's worth. For more efficient implementation you could use specialization if it ever stabilizes.

Point 2 would be great.

---

<div class="post-metadata">

**Author:** ![kpreid](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kpreid/32/8484_2.png) [@kpreid](https://internals.rust-lang.org/u/kpreid)\
**Post date:** [October 17, 2023, 4:32pm UTC](https://internals.rust-lang.org/t/adding-a-third-error-handling-type-for-when-no-added-context-is-needed/19722/14 "2023-10-17T16:32:43Z")

</div>

> [@SkiFire13](#):
>
> > [@Mokuz](#):
> >
> > I sometimes wish `()` implemented `Try` because then we wouldn't need both `for_each` and `try_for_each` a single function would suffice because
> 
> I think it's a bit too late for this, `for_each` has been stable for a long time and is not going away.

Currently being discussed:

> <https://github.com/rust-lang/libs-team/issues/187>
>
> \# Proposal
> 
> \## Problem statement
> 
> Using \`ControlFlow\<Self::T\>\` in a trait wh…ere most implementors set \`T = !\`. (or \`Result\<\_, Self::T\>\`) results in a lot of boilerplate for the implementer.
> 
> \## Motivation, use-cases
> 
> Visitors with an early return can be modeled as a trait such as the following (used in rustc):
> \`\`\`rust
> trait Visitor {
> type BreakTy = !;
> fn visit\_foo(&mut self, foo: &Foo) -\> ControlFlow\<Self::BreakTy\> {
> walk\_foo(self, foo)
> }
> // And more \`visit\_\*\` functions
> }
> 
> fn walk\_foo\<V: Visitor\>(v: &V, foo: &Foo) -\> ControlFlow\<V::BreakTy\> {
> // walk foo using \`?\` when needed
> Continue(())
> }
> \`\`\`
> 
> With non-branching implementations looking like (actual implementations can get worse):
> 
> \`\`\`rust
> impl Visitor for Bar {
> fn visit\_foo(&mut self, foo: &Foo) -\> ControlFlow\<!\> {
> if some\_condition() {
> // do something
> } else if something\_else() {
> // do something
> } else {
> walk\_foo();
> }
> Continue(())
> }
> }
> \`\`\`
> 
> \## Solution sketches
> 
> If \`Try\` and \`FromResidual\<!\>\` are implemented for \`()\`, then the previous example would instead be:
> \`\`\`rust
> trait Visitor {
> type ResultTy: Try\<Output = ()\> = ();
> fn visit\_foo(&mut self, foo: &Foo) -\> Self::ResultTy {
> walk\_foo(self, foo)
> }
> // And more \`visit\_\*\` functions
> }
> 
> fn walk\_foo\<V: Visitor\>(v: &V, foo: &Foo) -\> V::ResultTy {
> // walk foo using \`?\` when needed
> V::ResultTy::from\_output(())
> }
> 
> impl Visitor for Bar {
> fn visit\_foo(&mut self, foo: &Foo) {
> if some\_condition() {
> // do something
> } else if something\_else() {
> // do something
> } else {
> walk\_foo();
> }
> }
> }
> \`\`\`
> 
> Any impl which requires branching can then set \`ResultTy\` to \`ControlFlow\<T\>\` (or \`Result\<(), T\>\` if that makes more sense).
> 
> \---
> 
> An alternative would be to use a custom \`ResultTy\` trait implemented for both \`()\` and \`ControlFlow\<T\>\` (and others if needed). This would allow effectively the same interface, except anything which interacts with generic \`Visitor\`s wouldn't be able to use the \`?\` operator. This would mainly affect the implementation of \`walk\_\*\` functions which would otherwise make heavy use of it.
> 
> Downsides would be allowing \`foo()?????\` when \`foo\` returns \`()\`. This is easily solved with a lint any any use of \`?\` on an expression of the type \`()\`.
> 
> \## Links and related work
> 
> Came up on \[zulip\](https://rust-lang.zulipchat.com/#narrow/stream/233931-t-compiler.2Fmajor-changes/topic/Use.20.60ControlFlow.60.20in.20HIR.20.60Visitor.60.20compiler-team.23597) while discussing using \`ControlFlow\` more.
> 
> \## What happens now?
> 
> This issue is part of the libs-api team \[API change proposal process\]. Once this issue is filed the libs-api team will review open proposals in its weekly meeting. You should receive feedback within a week or two.
> 
> \[API change proposal process\]: https://std-dev-guide.rust-lang.org/feature-lifecycle/api-change-proposals.html

---

<div class="post-metadata">

**Author:** ![zackw](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/zackw/32/2071_2.png) [@zackw](https://internals.rust-lang.org/u/zackw)\
**Post date:** [October 17, 2023, 7:21pm UTC](https://internals.rust-lang.org/t/adding-a-third-error-handling-type-for-when-no-added-context-is-needed/19722/15 "2023-10-17T19:21:14Z")

</div>

> [@LThoerner](#):
>
> I need to know whether a function that would otherwise return nothing/`()` succeeded or failed, but not _why_ it succeeded or failed.

Frame challenge: I think you're _mistaken_ when you say you don't need to know why something failed. Please provide concrete examples of cases where, in your opinion, the root cause of the failure is unimportant, so we can assess them from our own perspectives.

(Full disclosure: _my_ perspective involves going on 30 years of trying to troubleshoot programs written by other people who didn't make their error reporting as detailed as it could have been.)

---

<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:** [October 18, 2023, 11:32am UTC](https://internals.rust-lang.org/t/adding-a-third-error-handling-type-for-when-no-added-context-is-needed/19722/16 "2023-10-18T11:32:18Z")

</div>

I thought implementing `Try` on `()` was a cool idea, until someone pointed out that it makes `println!()?` compile, even tough it doesn't do anything. That'd be super misleading. It will need ok-wrapping magic instead.

---

<div class="post-metadata">

**Author:** ![kpreid](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kpreid/32/8484_2.png) [@kpreid](https://internals.rust-lang.org/u/kpreid)\
**Post date:** [October 18, 2023, 2:10pm UTC](https://internals.rust-lang.org/t/adding-a-third-error-handling-type-for-when-no-added-context-is-needed/19722/17 "2023-10-18T14:10:53Z")

</div>

There could be a rustc lint against using `?` on the concrete `()` type.

---

<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:** [October 18, 2023, 3:48pm UTC](https://internals.rust-lang.org/t/adding-a-third-error-handling-type-for-when-no-added-context-is-needed/19722/18 "2023-10-18T15:48:32Z")

</div>

> [@kpreid](#):
>
> There could be a rustc lint

Yes, that was also brought up as a possibility in the ACP: [https://github.com/rust-lang/libs-team/issues/187#issuecomment-1745411419](https://github.com/rust-lang/libs-team/issues/187#issuecomment-1745411419)

---

<div class="post-metadata">

**Author:** ![Noratrieb](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/noratrieb/32/12440_2.png) [@Noratrieb](https://internals.rust-lang.org/u/Noratrieb)\
**Post date:** [October 18, 2023, 3:54pm UTC](https://internals.rust-lang.org/t/adding-a-third-error-handling-type-for-when-no-added-context-is-needed/19722/19 "2023-10-18T15:54:40Z")

</div>

`Result<(), ()>` being an antipattern is news to me. Well, it is indeed an antipattern, but the actual antipattern is not giving detailed errors. So your proposed enum is as much of an antipattern as `Result<(), ()>`. Type alias it to `Status` and you're good to go in the cases where you truly don't care (which is very rare!).

I see no reason to add a new type for this.

---

<div class="post-metadata">

**Author:** ![dlight](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/dlight/32/8462_2.png) [@dlight](https://internals.rust-lang.org/u/dlight)\
**Post date:** [October 19, 2023, 5:00am UTC](https://internals.rust-lang.org/t/adding-a-third-error-handling-type-for-when-no-added-context-is-needed/19722/20 "2023-10-19T05:00:42Z")

</div>

But the `Try` impl for `()` impl doesn't exist (and shouldn't exist IMO)

> **[Try in std::ops - Rust](https://doc.rust-lang.org/std/ops/trait.Try.html#implementors)**
>
> The \`?\` operator and \`try {}\` blocks.

[Next page](https://internals.rust-lang.org/t/adding-a-third-error-handling-type-for-when-no-added-context-is-needed/19722.md?page=2)
