[swift-evolution] Warning when "overriding" an extension method that's not in the protocol?
Chris Eidhof
chris at eidhof.nl
Thu Dec 10 16:43:24 CST 2015
Let's consider some subtle behavior when dealing with protocol extensions. We have a simple protocol:
protocol Shareable {
var myDescription: String { get }
}
Using an extension, we can add a quick function `share` that prints the social media description to the command line:
extension Shareable {
func share() {
print("Sharing: \(self.myDescription)")
}
func linesAndShare() {
print("----------")
share()
print("----------")
}
}
We can make string conform to `Shareable` by implementing the `myDescription`. This is all we need to do, we then automatically get the `share()` method for free. However, if we choose to, we can also create a custom variant of the `share` method. For example, if we make `String` conform to `Shareable`, we could do it like this:
extension String: Shareable {
var myDescription: String { return self }
func share() {
print("Special String Sharing: \(self.myDescription)")
}
}
Now, if we create a string and call `share()` on it, it will use our custom `share` method:
"hello".share()
// Prints "Special String Sharing: hello"
However, if we treat "hello" as a `Shareable` value, and then call `share()`, we get a very different result:
let hello: Shareable = "hello"
hello.share()
// Prints: "Sharing: hello"
Things get even more interesting. What happens if we call `linesAndShare` directly on a `String`?
"hello".linesAndShare()
// Prints:
//
// ----------
// Sharing: hello
// ----------
Coming from dynamic languages, you might be very surprised by the output of the last two examples. Even though we defined `share` on `String`, it did not override our default implementation. If we want to allow types conforming to `Share` to provide their own custom implementations, we need to specify `share()` in the protocol as well:
protocol Shareable {
var myDescription: String { get }
func share()
}
Now, we can still provide a default implementation of `share()`, yet allow other types to override the `share()` function.
If you've made it all the way through, I want to propose that we add a warning in case you override a protocol extension method that's visible in your scope (and has exactly the same type). For example, implementing `share()` in String could trigger a warning. In my experience, it's confusing that it looks like you're overriding it, but you're not really. I strongly believe the current behavior is correct, yet, it can be quite confusing, especially coming from ObjC.
Chris
More information about the swift-evolution
mailing list