Obviously, this does not compile. I'm getting the error 'rethrows' function must take a throwing function argument. Is there somehow a possibility, to initialise a struct with a function property, that may be throwing, and if it does so, then a method of that struct becomes throwing?
No, there isn't. Since you could have a var foo: Foo, the throwing-ness would have to show up in the type of the struct somehow, so that you can't accidentally copy a throwing-Foo into a non-throwing-Foo. But there's not a way to do that today (and no obvious way to add it to the language).
It's a bit of a shame, that we are still hold back sometimes by the language features, but on the other hand, it's like you've said...there is not really a straightforward way to put such a feature in the type-system.
struct Foo<E: any Error> {
let maybeThrowing: () throws E -> ()
init(_ maybeThrowing: () throws E -> ()) {
self.maybeThrowing = maybeThrowing
}
func bar() throws E {
try maybeThrowing()
}
}
var foo1 = Foo { print("Foo") } // Foo<Never>
foo1.bar()
let foo2 = Foo { throw Error() } // Foo<Error>
do {
try foo2.bar()
} catch {
print("Error")
}
foo1 = foo2 // error: Cannot assign value of Foo<Error> to variable of type Foo<Never>
Also note that existential type Error (aka any Error) does not conform to Error. So
for the Foo<Error> to work, we would need another feature, which is not yet implemented - Existential subtyping as generic constraint.
I'm glad to learn that this piece is already working, but on the other hand hardcoding magical behaviour for built-in protocols is disappointing. I think existential subtyping models this problem better.
Agreed, especially in a language like swift which tries to do as much as possible using normal code (we don't even have builtin types, which is awesome)
It is terrible, yes, but I can't think of a way to avoid copying everything that uses one of the two closure options. I think a generic type is better than two manual concrete types if there's other common functionality that doesn't rely on the closure.
struct Foo<Closure> {
private let closure: Closure
}
Actually, this is quite a genius workaround. I wouldn't have come up with that. It has some disadvantages, but hey...it's a workaround.
I still like the typed throws approach more and will bring up the discussion about Never in that thread again.
Self-conformance is limited to Swift.Error for now because it's a permanent limitation on the evolution of the protocol that we don't otherwise know how to express. When we figure out how to express it for other protocols, we can allow self-conformance then.