Read Rust

Tag: error-handling

Posts

This post describes my more-than-a-month long story of refactoring existing error definitions and error handling code in my largest project written in Rust. DICOM-rs is a pure Rust implementation of the DICOM standard, the near-ubiquitous standard for representing and communicating medical imaging data. The refactor hereby described on this project was an immediately apparent improvement, enabling me to track down the cause of a recently discovered bug in one of its crates.

error-handling

Error handling in Rust is very different if you’re coming from other languages. In languages like Java, JS, Python etc, you usually throw exceptions and return successful values. In Rust, you return something called a Result.

The Result<T, E> type is an enum that has two variants - Ok(T) for successful value or Err(E) for error value:

enum Result<T, E> {
Ok(T),
Err(E),
}

Returning errors instead of throwing them is a paradigm shift in error handling. If you’re new to Rust, there will be some friction initially as it requires you to reason about errors in a different way.

In this post, I’ll go through some common error handling patterns so you gradually become familiar with how things are done in Rust.

error-handling

Don’t panic! Learn to build quality software resilient to errors.

error-handling

Rust’s error handling is precise and curious - and in this article, we are going to take a look at why that is the case. I’ll introduce you to the basics of errors in Rust and then explain some more advanced concepts of dealing with errors.

error-handling

There has been much talk recently about "try fn" in Rust. This is to add some fuel to the fire and address one major argument against try-like sugar for functions: the special casing of Result.

This is explicitly not supposed to be a proposal. This is just meant to open discussion on a new avenue of the "try fn" design space I haven't seen mentioned yet.

error-handling

I’m a bit reluctant writing this, because it’s about a controversial and sensitive topic. Yet, after two days of sleeping on it, I hope this’ll hopefully not cause any more heated discussions and may help some mutual understanding.

This is in part triggered by this post by a blog post by withoutboats, in part by some twitter exchanges. So, let me start with this, as a response to withoutboats and everyone in the „Ok-wrapping camp“.

error-handling

Let’s begin with two excerpts from the paper Simple Testing Can Prevent Most Critical Failures: An Analysis of Production Failures in Distributed Data-intensive Systems

almost all (92%) of the catastrophic system failures
are the result of incorrect handling of non-fatal errors
explicitly signaled in software.
in 58% of the catastrophic failures, the underlying
faults could easily have been detected through simple
testing of error handling code.
These stats haunt me. They cause me to frequently ask myself “how can I design my systems to increase the chances that errors will be handled correctly?”

This leads to two goals:

when an error happens, it is handled correctly
error handling logic is triggered under test

error-handling

I’ve had a note in my to-do list to write down some of my own thoughts about error handling in Rust for quite some time and mostly got used to it sitting in there. Nevertheless, a twitter discussion brought it back to my attention since I wanted to explain them and honestly, twitter is just not the right medium for explaining design decisions, with its incredible limited space and impossible-to-follow threading model.

Anyway, this is a bit of a brain dump that’s not very sorted. It contains both how I do error handling in Rust, why I do it that way and what I could wish for. Nevertheless, my general view on the error handling is it is mostly fine ‒ it would use some polishing, but hey, what wouldn’t.

error-handling

I’ve long been a proponent of having some sort of syntax in Rust for writing functions which return results which “ok-wrap” the happy path. This is has also always been a feature with very vocal, immediate, and even emotional opposition from many of our most enthusiastic users. I want to write, in one place, why I think this feature would be awesome and make Rust much better.

error-handling

About two and a half years ago I wrote a Rust library called failure, which quickly became one of the most popular error handling libraries in Rust. This week, its current maintainer decided to deprecate it, a decision I strongly support. This week, I also released a new and very different error-handling library, called fehler. I wanted to discuss these two libraries briefly.

error-handling

Before we move on to parsing more of our raw packets, I want to take some time to improve our error handling strategy. Currently, the ersatz codebase contains a mix of Result<T, E>, and some methods that panic, like unwrap() and expect().

We also have a custom Error enum that lets us return rawsock errors, IO errors, or Win32 errors. First of all, I want to address something: When is it okay to panic?

error-handling

A programming language’s solution to error handling significantly influences the robustness, brevity, readability and – to an extent – the runtime performance of your code. Consequently, the error handling story is an important part of PL design. So it should not come as a surprise that the Rust community constantly discusses this topic. Given some recent discussions and the emergence of more and more error handling crates, this article shares some of my thoughts (not solutions!) on this.

error-handling

In our last adventure we looked at C++ exceptions in WebAssembly with the emscripten compiler. Now we’re taking a look at the main error handling system for another language targeting WebAssembly, Rust. Rust has a “panic”/”unwind” system similar to C++ exceptions, but it’s generally recommended against catching panics.

wasm error-handling

derive_more is a crate which has many proc macros, amongst which is a macro for deriving From for structs, enums, and newtypes. From is the basic mechanism for using ? ergonomically in a function which returns Result<T, Error>. Almost everything I write has the derive_more crate as a dependency, and the following pattern for handling errors.

error-handling

I’m planning to release a 1.0.0 version of failure on March 15. Once this happens, I don’t plan to release any further breaking changes to the failure crate (though maybe someday in the distant future).
Breaking changes in 1.0 failure is in a somewhat unique position as being a significant part of the public API of other libraries that depend on it. Whether they use the Error struct or derive Fail for a custom error type, this becomes a part of the API they expose to other users.

error-handling

View all tags