func wrap<E: Error>(fn: () throws E -> Void) rethrows E
became
func wrap<E: Error>(fn: () throws E -> Void) throws E
So as was said, every function and method has an implicit throws statement but when it is no declared, the compiler treats it as throws Never, so rethrows would keep its usage (and maybe future deprecation) over just throws notation.
It's an interesting scenario here, since this would/should mean that foo Doesn't throw if closure doesn't. It also shows us an interesting difference between typed rethrow and untyped rethrows:
Yeah, I mean, I think it can be totally possible and possibly a nonsense from the developer, as no Error will be passed through the outer method
I think the behavior obtained is totally what the developer declares in the syntax, so I don't see any issue there, but that's indeed a nice set of mix between typed and non typed.
Also, I see that it could be easily detected by the editor and raise a warning/error.
If we add typed rethrow, we should also figure out an easy syntax for functions that simply rethrow the arguments errors. It's unfortunate that this can't be the default, but it should greatly reduce the friction.
That said, I think it could be a whole 'nother proposal. Since we can just treat current rethrows as untyped.
Yeah I mean...an API is even changed without a new language version, which results in a source break as well. As long as the API-designer does not adopt typed throws, there is no source break.
IIUC the ABI issue that John raised is about deciding on the typed-throws equivalent for an untyped throws-rethrows signature today.
My point was that in Swift today, there is no function which accepts a throws T closure (since such syntax is illegal), so inferring T to be as specific as possible is not a source compatibility issue as far as I can see.
We would have the following three cases for rethrows (Or have I forgotten something?):
func foo(_ bar: () throws -> ()) rethrows // => Error (implicit, cause itâs same as bar)
func foo<E>(_ bar: () throws E -> ()) rethrows // => E (implicit, again itâs same as bar)
func foo<E>(_ bar: () throws E -> ()) rethrows CustomError // => different from bar, thus explicitly written
Seems consistent to me...
We could make a new rule for rethrows. Something like
rethrows throws an error of the same type as the closure argument, unless an explicit type is provided.
Rather than updating the current methods, we could just add the generic variant ones, which I think it does not break source compatibility, because non typed throws will always use the current version of the method:
// current
func map<T>(_ transform: (Element) throws -> T) rethrows -> [T]
// added
func map<T, E>(_ transform: (Element) throws E -> T) rethrows E -> [T]