This sort of near-miss bug for witnesses of protocol requirements with default implementations is really pernicious. Something narrowly tailored for the optional case seems potentially valuable, though we’d need a way to silence the diagnostic—backticks, I guess?
I’ve also seen this arise in cases where a defaulted requirement f is removed as a customization point (the default implementation remains), but a previous witness of f now becomes a shadowing declaration with different semantics. I would like if there were some way to say “this declaration witnesses some requirement” so that you’d get a warning/error in these sorts of scenarios. IMO dovetails nicely with formalizing @_implements as well.
This is reasonable. We already have something similar for @objc optional requirements, where a near-miss can also cause silent confusion; we silence the warning by moving the near-miss witness to a different context (extension vs nominal type) than the conformance itself. Another case we might want to warn about is when a subclass attempts to "override" a protocol requirement witnessed by a default implementation; in this case there's no vtable slot in the superclass:
protocol P { func f() }
extension P { func f() {} }
class C: P {}
class D: C { func f() {} } // not what you expect
This does have the downside that you wouldn’t be able to opt into the warning on a stored property if there’s a general policy of “declare conformances and their witnesses as separate extensions” since the stored properties would then ~always be separated from the extension where the conformance is declared.
I’m not going to defend return type overloading, but that’s why things are different here: inits do not allow overloading by failability but methods do. Of course, properties don’t allow overloading at all, so this isn’t a principled justification by any means; it’s just an explanation of why it happens to work for inits in the compiler implementation.
You can read the discussion in the Issue. It works for method overrides, so it could certainly work for protocol requirements; the trouble is it’s a source-breaking change, and a very subtle one at that. So at the very least it would have to be done in a new swift-version.
the difference with Int is that the type checker would likely prevent you from accidentally calling the wrong overload. whereas there is nothing preventing the wrong overload from being called here:
Int/String was just an example, here's another one:
class I {}
class S: I {}
protocol Nominal {
var name: S { get }
}
extension Nominal {
var name: S { S() }
}
struct Struct: Nominal {
var name: I { I() }
}
let x: Nominal = Struct()
let name1: S = x.name
let name2: I = x.name
print(type(of: name1)) // S
print(type(of: name2)) // S
// compiler is happy, no warnings
The point of these examples to show it's not just about Optional.