Because if it's in the actual language the compiler can enforce it. As it does today. So the same benefits as static typing in general (although not of as much benefit as, e.g. knowing that a variable is a number and not a string).
From a user perspective, machine-validated is usually better than unvalidated. Documentation is great except when it's outdated or flat-out wrong (SingleValueDecodingContainer et al), which is all too often. I love documentation because it can be game-changing, when done right, but I also hate it because most of the time it's done wrong (or not at all).
But validation isn't magically free - from a compiler-author perspective, for example, it may be much less attractive in some cases. I gather rethrows
might be one of them, given @Douglas_Gregor bringing up this existential question about rethrows
to begin with. It sounds like it's hard to actually implement rethrows
and typed throws together.
Indeed.
And it's a little like throwing vs non-throwing to begin with. If you have a function func foo(…) {}
- no throws annotation - you know you can call it and it's "transparent", in an error-handling sense. It's not something you need to worry about in terms of failure origin points within your program. Whereas func bar(…) throws {}
has to be approached more carefully - not just syntactically with the required try
keywords etc, but logically as you design your program and reason about its failure modes. You have to ask questions like "what should my program do if this specific thing fails - what does it mean if this things fails?", "how do I present this to the user?", etc.
So a function that rethrows
[only] is also "transparent" in this sense. You do still have to use try
etc, but the function is merely on the path of errors, not an origin of errors. So it doesn't add any additional burden to your design-level thinking w.r.t. failure modes.
It depends on the definition of E
. For the most generic case - E: Error
- indeed I don't see a realistic way for f
to make a new one. But one certainly can constrain E to a protocol that facilitates it. e.g.:
/// Enhanced error protocol for all Acme Corp libraries,
/// that provides important fundamental error functionality.
protocol StandardError: Error {
…
static func missing(argument: String,
function: String = #function,
file: String = #file,
line: Int = #line) -> HandyError
…
}
func f<E: StandardError>(_ g: () throws(E) -> Void) throws(E) {
throw E.missing(argument: "g")
}
Now, how common or useful that is, I dunno. My own use of errors tends to be pretty straight-forward, largely just plain error enums. But I write Swift solo, not as part of a big company. And big companies have amazing abilities to complicate everything, for better or worse.