Functional extensions for result

In an earlier post, I created Result<TValue, TError>, a generic, allocation-free struct that lets code avoid using exceptions for control flow. On its own, it supports only a procedural style, where each call is followed by a check of Success or Failure. A few steps in, most of the code is branching. Functional programming offers a way to hide the branches from the calling code. Instead of checking a result, the code composes operations on it. The operations do the checking. F# ships a Result module for exactly that. In this post I implement C# counterparts of its functions for Result<TValue, TError> as extension methods: map, mapError, bind, iter, iterError, defaultValue and defaultWith. I also add Match, an addition of my own. With these methods, steps can be chained without checking Success or Failure after each call. ...

September 24, 2026 · 9 min · 1717 words · gabrielius837

Result Pattern in C#

Introduction In C#, I handled every edge case that strayed from the happy path by throwing an exception. That worked at first, but each new edge case meant another exception type in the error handling middleware. Composing methods to reuse functionality got harder. Exceptions also aren’t cheap: throwing one measurably costs more than returning a value. Nor should they be relied on for control flow. I also tried Go. An if err != nil after every call looks like boilerplate, but that boilerplate is the point: a function’s signature reflects whether it can fail and the error gets handled right there instead of somewhere else. It’s explicit where exceptions are indirect. There’s no need to know about a try/catch further up the call stack. I wanted that same explicitness in C#. ...

September 15, 2026 · 9 min · 1729 words · gabrielius837