Yup, I admit that was kind of a rhetorical question, because with the way generics work in Swift, this couldn't behave any differently unless try?
did some run-time checking for whether the value is actually an Optional and nil.
And that's the consistency argument: With the proposed change, this code:
func doInBackground<T>(
_ fn: @escaping () throws -> T,
then: @escaping (T) -> Void,
onError: @escaping () -> ()
) {
DispatchQueue.global().async {
guard let res = try? fn() else { onError(); return }
then(res)
}
}
will behave wildly different than the same code, just replacing T
with a concrete type:
func doInBackground(
_ fn: @escaping () throws -> Data?,
then: @escaping (Data?) -> Void,
onError: @escaping () -> ()
) {
DispatchQueue.global().async {
guard let res = try? fn() else { onError(); return }
then(res)
}
}
I'm not sure we have any other construct that changes behaviour this much depending on the types/when generics are "manually specialized" (does anyone have examples?), but I do know that in my opinion this would make try?
's behaviour inconsistent and hard to reason about, even ignoring the conflation of errors and result values.