In my opinion, the difference between errors as return values and checked exceptions is merely one of syntactic sugar. Both are conceptually a sum type together with the regular return value, and the syntactic sugar for handling and/or propagating the error or exception is really a spectrum, not a dichotomy. I believe it would be useful to focus on the possible design choices within that spectrum, regardless of the underlying implementation mechanism.
Of course, the implementation mechanism matters at the machine code level or in the runtime. However, that is mostly a question of performance trade-offs and interoperability, but otherwise just an implementation detail, and doesn’t have to be a question of expressiveness and code-level semantics. You can implement exceptions as subroutine return values, and you can implement error return values with exception-like mechanisms behind the scenes. That should be a different concern from how it looks like at the source-code level.
The main caveat is that oftentimes, checked exception handling doesn't compose well - see what kind of trouble Java gives you, for example.
Recent articles I've read on effect modeling languages seems to give a more uniform construct for bringing checked exceptions in line with other control constructs.
> see what kind of trouble Java gives you, for example.
I program a lot in Java, and the only trouble there is the lack of support for sum types and/or variadic type parameters in generics (i.e. to express functional interfaces that can throw an arbitrary number of checked exceptions, as a type parameter). That’s the only pain point for me and is something that could be fixed.
In fact, the interplay with control structures is exactly what I was referring to by
syntactic sugar. Indeed it also concerns the type system.
But let’s talk about that, not about exceptions good/bad or error values good/bad. That’s too simplisitic.
I mean, syntactic sugar is one thing, but being entirely incapable of creating variadic exceptions really hamstrings you in places where you don't wish to write a great deal of redundant code for each combination of exceptions you may see.
Completely agreed about variadic exceptions, but that's not a drawback of exceptions, it's a limitation of Java's supported syntax for generics. In catch clauses, Java already has exception sum types (`catch (FooException | BarException ex)`), and Java also has variadic method parameters, so why not have variadic type parameters, maybe something like `Foo<V extends Bar, T... extends Throwable>` that can be instantiated as `Foo<SomeBar, BazException | QuxException>`.
Yep! I'd love to see something like this in Java, but it's unlikely, probably for the usual runtime type erasure reasons. Exceptions can be implemented in this way, and would strike a nice balance in doing so.
Of course, the implementation mechanism matters at the machine code level or in the runtime. However, that is mostly a question of performance trade-offs and interoperability, but otherwise just an implementation detail, and doesn’t have to be a question of expressiveness and code-level semantics. You can implement exceptions as subroutine return values, and you can implement error return values with exception-like mechanisms behind the scenes. That should be a different concern from how it looks like at the source-code level.