To be fair, your example shows a protocol which already allows its next()
method to throw and simply allows non-throwing methods to witness the requirement. It's convenient, but you don't need typed-throws for that; in fact, I think it already works.
I don't think the solution proposed by OP is all that useful - I think we actually have a better thing, right now (Swift 4.2), but I don't think everybody is aware of it, so let me explain:
You can create a parent protocol, whose requirements can throw, and also a non-throwing refinement. The compiler will already recognise these as being the same, so you don't even need to write a default implementation with the throwing signature (see example). However, generic code will be able to require a non-throwing witness if your algorithms are not fault-tolerant. I think it's a cleaner solution.
We could do something like this in the standard library, except that ABI stability bans re-parenting protocols, and Sequence/IteratorProtocol
kind of have knives dangling above their heads already.
protocol MightThrowIterator {
mutating func next() throws -> Int
}
protocol NoThrowIterator: MightThrowIterator {
mutating func next() -> Int
}
struct A: MightThrowIterator {
enum Err: Error { case anError }
mutating func next() throws -> Int {
throw Err.anError
}
}
struct B: NoThrowIterator {
mutating func next() -> Int {
return 42
}
}
func tryIterate<T: MightThrowIterator>(_ val: inout T) {
do {
let element = try val.next()
print(element)
} catch {
print(error)
}
}
func definitelyIterate<T: NoThrowIterator>(_ val: inout T) {
let element = val.next()
print(element)
}
func test() {
var testObjA = A()
var testObjB = B()
tryIterate(&testObjA) // prints: 'anError'
tryIterate(&testObjB) // prints: 42
definitelyIterate(&testObjA) // Compile error: 'A' does not conform to expected type 'NoThrowIterator'
definitelyIterate(&testObjB) // prints: 42
}