|
|
|
|
|
by heavenlyhash
2992 days ago
|
|
I think part of the insidiousness of exceptions is that we're tempted to think there's a way to use them that's not as a flow control mechanism. And there isn't. That's what they do: _alter flow_. A sibling comment hints at the way out: > For exceptions to work predictably, all mutation within a try-catch block should be captured in a transaction that can be rolled back. The instant an exception can be raised from an area in code is the instant you need to make that entire area into functionally-pure side-effect-free logic, so that you can reason about it even when the exception is raised. And then you've got a function that could just as well return an Either<Result, Error> -- what a strange "coincidence"! |
|
I mean, that would be lovely, but is really only feasible for exceptions raised from code that is operating exclusively on values in memory (NPEs, for example). Rather a lot of exceptions are raised from necessarily side-effectful operations, especially those dealing with I/O.
Since you can't predict the future, you can't guarantee purity/transactionality of code that raises that kind, so saying "code should be pure when it can throw" is a true-but-impossible statement. That's why most languages with an emphasis on purity tend to eschew exceptions and/or invert control flow such that effectful stuff happens externally to the functions handling its output (e.g. the Maybe or IO monads).