Back in 2016 I had an idea. What if I put Rust code inside Haskell? Not long after that I had another idea. What if I put Haskell code inside Rust? With that the library curryrs (pronounced couriers) was born with the goal of making FFI between the two languages easy and to let the user spend less time mucking around with types and more time actually coding. However, this all broke when cargo changed it's behavior regarding rpaths for dynamic linking back some time in ~2017. Like many of my projects, I let it languish because I just couldn't fix it at the time and I was still relatively junior as a coder at my job and was finishing up my CS degree. I attempted it again in 2018 and for multiple reasons failed to get it to work again. curryrs languished for all of 2019 and I had archived the code at that point in time. A lot of the failure just came down to not understanding linking and just not enough knowledge around computers. Then this year in the midst of COVID-19 I got a brain itch.
This is mostly what causes me to try wild ideas that I work on obsessively until I solve it, like when I put the Haskell runtime in Rust. That level of working on the edge of no documentation really, cryptic clues, and can it even be done has driven me to do things just to prove I can.
The comparisons we will see is not meant to show if one approach is better than another. Instead, it is intended to be a reference to become familiar with common patterns across multiple languages. Throughout this post we will utilize several tools and libraries.
GHC Haskell supports a feature called asynchronous (or async) exceptions. Normal, synchronous exceptions are generated by the currently running code from doing something like trying to read a file that doesn't exist. Asynchronous exceptions are generated from a different thread of execution, either another Haskell green thread, or the runtime system itself.
Rust does not have exceptions at all, much less async exceptions. (Yes, panics behave fairly similarly to synchronous exceptions, but we'll ignore those in this context. They aren't relevant.) Rust also doesn't have a green thread-based runtime like Haskell does. There's basically no direct way to compare this async exception concept from Haskell into Rust.
Or, at least, there wasn't. With Tokio, async/.await, executor, tasks, and futures, the story is quite different. A Haskell green thread looks quite a bit like a Rust task. Suddenly there's a timeout function in Tokio. This post is going to compare the Haskell async exception mechanism to whatever powers Tokio's timeout. It's going to look at various trade-offs of the two different approaches. And I'll end with my own personal analysis.
View all tags