• But I find this description to be really poor. Exceptions are values, what this is actually describing is the locality of control-flow.

    That’s a good point. I used that phrasing as I expect it easier to understand that result monad, but it is conveying the wrong thing we care about, which is treating the error path a part of the normal control flow.


    The answer is, yes when I write an Operation object with a monadic interface I capture exceptions inside it and translate them into Result monads. This is very easy to do. It makes the Operation object a boundary where I can actually provide a level of certainty that exceptions raised are truly exceptional.

    I know it is straight-foward to map things, but it is hard to do so exhaustively as Ruby gems use exceptions for all sorts of things. So one either has to convert all StandardError exceptions or have to deal with the problems of using exceptions for control flow. Maybe the wide-net approach doesn’t lead to any issues?


    score 1 · canonical

    • Some libraries are more well-behaved than others and define a top-level Error class. Those that don’t (looking at you, jwt) are annoying but often just tagging what step in the process raised is sufficient to know how to handle it. I usually have an all-else-fails rescue for StandardError that I log for better handling.

      The benefit is that you get to choose how granular your handling needs to be. Going all-in on exceptions-as-control-flow leads to an explosion of possible branching paths that is unsustainable; but using Results allows you to compress layers into fewer choices.

      I view the tradeoff here as similar to using case…in pattern matching: okay sure it’s not exhaustive in the same way as other languages, but it’s still a meaningful improvement.


      score 1 · canonical