# Rust has no Exceptions?

**URL:** <https://discourse.haskell.org/t/rust-has-no-exceptions/10729>\
**Category:** Learn\
**Created:** [November 13, 2024, 1:10pm UTC](https://discourse.haskell.org/t/rust-has-no-exceptions/10729 "2024-11-13T13:10:14Z")\
**Posts on this page:** 9\
**Page:** 2

<div class="post-metadata">

**Author:** ![Ambrose](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/ambrose/32/5672_2.png) [@Ambrose](https://discourse.haskell.org/u/Ambrose)\
**Post date:** [November 14, 2024, 12:33am UTC](https://discourse.haskell.org/t/rust-has-no-exceptions/10729/21 "2024-11-14T00:33:50Z")

</div>

Async exceptions in particular are why Haskell is better than Rust or Go for concurrency. It just has a better concurrent RTS with fewer footguns.

And as others have said, Rust doesn’t ensure code doesn’t `unsafeExplode`

---

<div class="post-metadata">

**Author:** ![atravers](https://avatars.discourse-cdn.com/v4/letter/a/45deac/32.png) [@atravers](https://discourse.haskell.org/u/atravers)\
**Post date:** [November 14, 2024, 5:54am UTC](https://discourse.haskell.org/t/rust-has-no-exceptions/10729/22 "2024-11-14T05:54:22Z")

</div>

> [@mmport80](#):
>
> But apparently idiomatic [Rust] code more or less assumes reliable type definitions… I have to say this is very nice, and something I wish Haskell put (even) more attention on.

As it so happened, someone recently expressed a similar interest for I/O:

> [@IO without exceptions?](http://discourse.haskell.org/t/io-without-exceptions/9922):
>
> About a year ago, I wrote a proposal for IOE, enabling checked exceptions in IO. It got fairly negative reactions, which is fine. This is a smaller change that I think might be less controversial than that. Currently, we have IO that represents both impurity and the ability to throw exceptions. Here, I’m only talking about exceptions in the Haskell runtime; OOM and other catastrophic errors can also happen in pure code, so I’m not worried about those. What if we had some new type e.g. UIO that …

But in the context of Haskell, what exactly is _“idiomatic code”_ ?

- effect-free expressions? Haskell is nonstrict, which is why **it’s** so nice to program in. Hence the lack of those effects `(`unless something `unsafe...` is being used`)-;`

- the absence of effect-centric actions (functorial, applicative, monadic, arrow, comonadic _et al_ )? Alright, just provide some other way to manage exceptions or other effects in Haskell (and remember: even _effect systems_ rely on one or more of those interfaces - usually the monadic one).

Otherwise, perhaps this could be of interest:

> **[dialogue](https://hackage.haskell.org/package/dialogue)**
>
> I/O in Haskell Report 1.2

(with abstract monadic I/O first appearing officially in [Haskell 1.3](https://www.haskell.org/definition/haskell-report-1.3.ps.gz)).

Instead of `IO a`, a program would have the type:

```haskell
type Dialogue = [Response] -> [Request]

```

…it would be one big effect-free expression, with all that imperative ugliness confined to the interpreter (which does use abstract monadic I/O). But since Haskell 2010 also provides an FFI:

```haskell
foreign import ccall runDialogue :: Dialogue -> IO ()

```

`(`if the in-Haskell interpeter is too slow `;-)`

---

<div class="post-metadata">

**Author:** ![tomjaguarpaw](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/tomjaguarpaw/32/1230_2.png) [@tomjaguarpaw](https://discourse.haskell.org/u/tomjaguarpaw)\
**Post date:** [November 14, 2024, 8:39am UTC](https://discourse.haskell.org/t/rust-has-no-exceptions/10729/23 "2024-11-14T08:39:16Z")

</div>

This is very interesting, because `variant` is using an analogous encoding to `effectful` anyway. For example, see [the definition of `V`](https://hackage.haskell.org/package/variant-1.0/docs/Data-Variant.html#v:V)

```haskell
V :: c :< cs => c -> V cs 

```

and note the resemblance to the [`effectful`](http://discourse.haskell.org/t/rust-has-no-exceptions/10729/15) type signature I gave. If you use `variant` for exceptions then you start with separate constructor types `c` satisfying `c :< cs`, wrap them up in a `V cs`, and then later unwrap them to handle them. But if you’re using `effectful` then you may as well keep them all separate as `Error c :> es` constraints and avoid the middleman of wrapping and unwrapping!

---

<div class="post-metadata">

**Author:** ![jeukshi](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/jeukshi/32/4040_2.png) [@jeukshi](https://discourse.haskell.org/u/jeukshi)\
**Post date:** [November 14, 2024, 6:00pm UTC](https://discourse.haskell.org/t/rust-has-no-exceptions/10729/24 "2024-11-14T18:00:19Z")

</div>

> [@danidiaz](#):
>
> [“Open inversion of control demands exception transparency”](https://medium.com/97-things/uncheck-your-exceptions-ec37a722f5ad) by Kevlin Henney

The author fails to convince me that there is some principle involved. In the last paragraph, he even mentions how to deal with checked exceptions, which brings me to this:

[The Trouble with Checked Exceptions](https://www.artima.com/articles/the-trouble-with-checked-exceptions)

There are a few points here, but the main is, IMO, that people just don’t care to handle all of those exceptions. They either don’t care because they have some exception handler in place already (provided by a web framework, for example) or they just want to stay on the happy path and build that useful functionality. They will circumvent checked exceptions anyhow, and it is only trouble for them that they have to do that.

Whenever Go folks call `if err != nil` exception handling, I’m in disbelief. Just a quick search on GitHub, they either do `panic(err)` or `return nil, err` or `myLogger.Fatal(err)`. I’m sure there are examples of actual exception handling, but most aren’t. The three above are just exceptions with extra steps, code that could be added by the Go compiler. I just don’t see the benefits.

Now Rust might be different due to its goals (close to metal/exceptions don’t mix?), but a quick look at [Rust book](https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html) and the first example of exception handling is this.

```rust
fn main() {
    let greeting_file_result = File::open("hello.txt");

    let greeting_file = match greeting_file_result {
        Ok(file) => file,
        Err(error) => panic!("Problem opening the file: {error:?}"),
    };
}

```

To be fair, this is what I would do in Haskell if `open` returned `Either`.

That being said, I really like checked exceptions, if I want to force myself to do something consistently. Forcing others just doesn’t work that well.

---

<div class="post-metadata">

**Author:** ![tomjaguarpaw](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/tomjaguarpaw/32/1230_2.png) [@tomjaguarpaw](https://discourse.haskell.org/u/tomjaguarpaw)\
**Post date:** [November 14, 2024, 6:57pm UTC](https://discourse.haskell.org/t/rust-has-no-exceptions/10729/25 "2024-11-14T18:57:20Z")

</div>

> [@DavidB](#):
>
> a sensible `throw` operation needs to also be passed a capability, and this capability/continuation must be tracked in the type system, which makes it possible again to use linear logic reasoning.

Hmm, I’m not sure it makes it possible again to use linear logic reasoning. Even if we use Bluefin, say, where an exception can only be thrown if there’s a suitable capability in scope, and even if we completely avoid imprecise exceptions (i.e. from pure code), I still don’t see we can use linear logic reasoning. We can still write

```haskell
\ex -> do
  r <- acquire
  throw ex MyException
  release r

```

and lose access to `r`, so we can’t release it. Nonetheless, we could bracket the ability to acquire `r`, and put _some_ bounds on the lifetime of `r`, but it still doesn’t seem like linear logic reasoning to me. Maybe I’m misunderstanding you though.

---

<div class="post-metadata">

**Author:** ![atravers](https://avatars.discourse-cdn.com/v4/letter/a/45deac/32.png) [@atravers](https://discourse.haskell.org/u/atravers)\
**Post date:** [November 15, 2024, 9:37am UTC](https://discourse.haskell.org/t/rust-has-no-exceptions/10729/26 "2024-11-15T09:37:15Z")

</div>

Since it’s already been mentioned three times…in section 3.3 of [How to Declare an Imperative](https://ics.uci.edu/~jajones/INF102-S18/readings/24_wadler) (_Interaction by linear logic_, pages 21-24 of 33), Philip Wadler provides an example based on uniqueness types rather than just linear parameters. This is an interesting choice, given that Wadler’s previous literature (for example, [Linear types can change the world!](https://web.archive.org/web/20151102061631/https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.31.5002&rep=rep1&type=pdf)) advocated the use of linear parameters.

But in this topic, the term _“linear logic”_ has only been associated with linear parameters (presumably because only those are provided by Glasgow Haskell). So could it be _this specialisation of_ linear logic (rather than linear logic itself) which is at fault, with regards to breakage of reasoning?

---

<div class="post-metadata">

**Author:** ![sgraf](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/sgraf/32/392_2.png) [@sgraf](https://discourse.haskell.org/u/sgraf)\
**Post date:** [November 15, 2024, 10:33am UTC](https://discourse.haskell.org/t/rust-has-no-exceptions/10729/27 "2024-11-15T10:33:54Z")

</div>

> [@tomjaguarpaw](#):
>
> lose access to `r`

I think this is what David wants to prevent when he writes

> [@DavidB](#):
>
> so a sensible `throw` operation needs to also be passed a capability, and this capability/continuation must be tracked in the type system, which makes it possible again to use linear logic reasoning.

I would think that you need to associate “cleanup handlers” with `ex` for every linear resource that is in scope at a use site of `ex`. Such a cleanup handler would consume the particular resource upon unwinding, triggered by a call `throw ex`.

It seems quite complicated to support this (i.e., “ensure that every use of `ex` comes with a cleanup handler of linear resources”) in the type system.

Perhaps a `finally` or `bracket`-like combinator could avoid this reasoning, but how do we ensure that this combinator affects _all_ exception effects in the `Eff` stack?

(I suppose this has been discussed in the effect systems research community before, which is why I’ll defer to David here :).)

---

<div class="post-metadata">

**Author:** ![emlautarom1](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/emlautarom1/32/4080_2.png) [@emlautarom1](https://discourse.haskell.org/u/emlautarom1)\
**Post date:** [November 16, 2024, 5:51am UTC](https://discourse.haskell.org/t/rust-has-no-exceptions/10729/28 "2024-11-16T05:51:29Z")

</div>

I think the main problem with the reasoning of tracking exceptions at the type level is that they break encapsulation when working with higher order functions (the bread-and-butter of FP): If I have a function that requires an operation that provides the current time, how do I handle different implementations that might or not fail? Knowing precisely how it might fail requires the consumer to be coupled to a specific implementation so the usual approach is to say “this operation might fail”, yet this is not very helpful since everything could technically fail. At the end you end up with something like go’s `error`, something opaque that at best you can print.

---

<div class="post-metadata">

**Author:** ![atravers](https://avatars.discourse-cdn.com/v4/letter/a/45deac/32.png) [@atravers](https://discourse.haskell.org/u/atravers)\
**Post date:** [November 16, 2024, 6:43am UTC](https://discourse.haskell.org/t/rust-has-no-exceptions/10729/29 "2024-11-16T06:43:15Z")

</div>

> [@](#):
>
> I think the main problem with the reasoning of tracking exceptions at the type level is that they break encapsulation when working with higher order functions (the bread-and-butter of FP): If I have a function that requires an operation that provides the current time, how do I handle different implementations that might or not fail?

I would have thought something like [`Throws e m`](https://hackage.haskell.org/package/encoding-0.8.9/docs/Control-Throws.html) does that - for example:

```haskell
{- Exception e => Throws e IO -}
data TimeFailure = ... -- or a newtype
instance Exception TimeFailure

```

How to make that work in an effects system is left as an exercise…

[Previous page](https://discourse.haskell.org/t/rust-has-no-exceptions/10729.md?page=1)
