Pre-RFC: Catching Functions

One of the chief ergonomic advantages I failed to layout in the original post was that this proposal is designed to have a very small edit distance when introducing fallibility to a function.

In my experience, this isn't an uncommon experience. As an example, some unit of code which previously was pure now needs to do some IO (say because its pulling a value from some sort of shared cache that it used to compute). Maybe this isn't the best design and all IO should be segregated from logic etc etc, but in real systems these sorts of things happen, whatever.

Today, there is a significant amount of purely boilerplate edits you have to make to enable this. In addition to the actual material changes you're making, you have to change the return type of the function and find every place it returns and wrap them all in Ok. When I have the misfortune of making these edits in a function that ends with a match statement, I'm often tempted to use a regex - to mixed results usually.

But all of this could be eliminated - you add the code you want, you add catch ErrorType to the function signature, you handle the error everywhere it is called (probably by ?). In other words, we reduce the edit distance to the material changes being made to the code.


The interaction with async/await is one of the key insights that makes this proposal work well. Though the async/await RFC was experimental, it's extremely well motivated and its hard to imagine a world in which we don't someday have a form of async function which appears to return a result and actually returns a future.

Which types? Result and Future are important to support because they are pervasively important in real code. The weakly supported one here is Option, its true. I'm not convinced that "some wrapping" is so important though, for these reasons:

  • Its not that common for a function that unconditionally returned T to switch to returning Option<T>, not in the same way that becoming fallible is common.
  • When I write functions that return Option<T>, in my experience the terminal expression is usually None, whereas in result functions the terminal expression is usually Ok(result). In other words, the "happy path" is less predominant in most functions I write that return an Option.

Do you have other pervasively used types that you think an ok-wrapping feature needs to be able to support to be worthwhile? Why is it important to support these types?

4 Likes