But crossing interfaces between modules is, IMO, core to exceptions. They're ideally suited to communicating the underlying cause of failure from the depths of the system to the top-most loop (usually a request/response dispatcher or UI event loop), where the error message can be logged or shown to the user, as required, indicating the nature of the failure.
I expounded further on this point a few years ago, related to Java's misadventure with checked exceptions, but also relevant to module crossing:
"The convention in the Go libraries is that even when a package uses panic internally, its external API still presents explicit error return values"
http://blog.golang.org/2010/08/defer-panic-and-recover.html
But crossing interfaces between modules is, IMO, core to exceptions. They're ideally suited to communicating the underlying cause of failure from the depths of the system to the top-most loop (usually a request/response dispatcher or UI event loop), where the error message can be logged or shown to the user, as required, indicating the nature of the failure.
I expounded further on this point a few years ago, related to Java's misadventure with checked exceptions, but also relevant to module crossing:
http://cafe.elharo.com/programming/bruce-eckel-is-wrong/#com...