3 ms·
At first, I thought this was going to be an article about having zero exceptions, because exceptions aren't allowed, perhaps due to a type system. This isn't r
by acjohnson55 11y ago
At first, I thought this was going to be an article about having zero exceptions, because exceptions aren't allowed, perhaps due to a type system.
This isn't really possible in a language that doesn't have type annotations, because in such a language, you can't make any run-time assumptions. All bets are off! Anything could be undefined! Anything might throw at any time!
In a language like Scala, you can almost completely eliminate the possibility of exceptions. You just have to be disciplined about never throwing. If you always use types that represent the possible outcomes of an operation or the valid inputs a module might accept, then you're forced to handle every possibility, and you're forced to eventually converge all your code paths to produce an output value from some bounded set. The more tightly bounded, the better! (Granted, the Scala type system doesn't guarantee that a function won't throw, and some standard library functions do throw, so all isn't perfect.)
Don't want to deal with all the cases right away? No problem, don't throw, just coerce the result to some temporary default value.
If you're disciplined enough in this approach, you'll eliminate all business logic exceptions. You'll still have to worry about errors in the underlying runtime, like OutOfMemoryError, but those you can defer to the operations tier.
- sbov 11y agoI'm not sure what the recommended alternative to this scenario would be based upon your comment: I like to check invariants at certain points in my code. Them not being correct is an obvious bug. I would prefer to fail in the most obvious fashion if they aren't correct, which for our production environment is an exception.
- joslin01 11y agoI wrote the first version of the API I'm currently working on in that exact mindset in Scala with the Play framework. It basically boils down to everything returning `Either[Error, X]` where X is whatever the service is returning. I came to dislike this approach because most of the time the error doesn't happen and it's just wasted code that's a bit verbose. So now I'm moving into Akka and going to allow well-defined exceptions to throw that get handled by a supervisor. It was nice to know errors were handled, but I came to the opposite opinion that exceptions truly are exceptional and errors are an instance of the exceptional taking place. Shrug, the bottom line is being disciplined in error-handling. I know there's varying views on this approach, but I really like crafting method signatures that indicate what they are intended to return rather than `Either` for everything. There's places where `Either` is great like registration where a bad password isn't really an "exception" but user error.
- PeCaN 11y agoI think (?) Scala has proper monads (but they're a little weird) which would let you avoid the verbose extra code. Generally it just involves implementing map and flatMap on your Either type, or something like that. Disclaimer: not a Scala developer.
- acjohnson55 11y agoIf you don't really care about the details of the unhappy path, just use Option. The real problem with exceptions is that they crash the whole program, but it's really difficult to know you've accounted for all possible exceptions. With pattern matching on an Option, Either, or Validation, you'll get a compile-time warning if you haven't accounted for all branches. Checked exceptions, like in Java, also have this property, they're just really awkward to use.