Rust is a language I’ve admired for a long time now, from a slight distance. I’ve read about the borrow checker, perused the standard crates, and read up on Cargo and the way that Rust applications and libraries are built, tested, and shipped. I appreciate its striving to be a systems-level language that also cares about safety and developer productivity.
I haven’t written as much Rust as I’d like to (though I did start a few small
projects here and there), but that didn’t stop me from thinking that maybe some
of its standard library features have a place in the C# world. I found myself
particularly fond of the Option and Result types, and
their ability to better the flow of my code. Option’s API is
steroids, and Result provides an elegant way to express an error that doesn’t
require using out parameters or custom exceptions, while at the same time
providing a delightful API that lets you build processing pipelines that
preserve errors and lazily evaluate steps.
The adventure started when one afternoon about a month ago, when I decided I
wanted to see if I could implement
Option in C#. I knew I wanted to preserve
as much of the Rust API as made sense, including the simple construction of
None as function calls:
None<int>(), etc. I opened
up Workbooks (use what you know, right?) and started hacking away.
After a little while, I had my first pass at the
Option API surface—I
stuffed it in a Gist, Within a few hours, I decided to make it into a
library called Oxide—after all, what else is Rust?
My initial commit brought in the API almost exactly as it was in the
Gist. Over the rest of the day, I refined the API slightly, added a ton of tests
(inspired by the Rust documentation’s example assertions), and wrapped up. A
week later, I decided to add
Result, which I implemented largely the same way
(a base class, with derived
Ok<T, E> and
Err<T, E> classes).
Since then I’ve refined the API for both, added a priority queue implementation, added a small library of HTTP helper methods (Oxide.Http), received my first external contribution from Jérémie Laval who contributed a very nice set of convenience methods to enable async/await with Option, and finally published a NuGet (when I was forced to by wanting to use Oxide in another project but wanted to avoid submodules).
I hope to keep working on Oxide—there will probably be more APIs that I would like to borrow from Rust, or more functional/Rust-inspired API that would be useful for C# developers. Contributions of all kinds are welcome: bug reports, feature requests, documentation, etc. You can find Oxide on GitHub—please use the issue tracker there for everything. :)