[swift-evolution] Mark protocol methods with their protocol
David Beck
swift at tnku.co
Fri Sep 16 10:29:21 CDT 2016
With the transition from Swift 2 -> 3 I’ve started running into one particular issue VERY often (although it’s not necessarily specific to the transition). If a protocol method is optional (either because it is an @objc optional or because it has a default implementation) there is a risk that the conformer will have a misspelled or slightly incorrectly typed implementation of the method. For instance:
protocol RouteDestinationViewController: class {
static func viewController(with url: URL, properties: [String:String]) -> UIViewController?
}
extension RouteDestinationViewController where Self: UIViewController {
static func viewController(with url: URL, properties: [String:String]) -> UIViewController? {
return Self.init()
}
}
class FooController: UIViewController, RouteDestinationViewController {
static func viewController(with url: URL, properties: [String:Any]) -> UIViewController? {
return FooController(properties: properties)
}
}
Notice the issue there? Properties is supposed to be [String:String], but FooController uses [String:Any] (this is an exact issue I ran into after a small refactor). When viewController(with:properties:) is called, it will use the default implementation instead of what the compiler sees as a completely different method. Over the betas the compiler has gotten better warnings about this, but is still not 100%.
Other cases of this issue are common with imported ObjC protocols that have different naming in Swift. In some cases an @objc name must be applied to ensure it is declared in a way that the protocol can see it.
We solve this problem with subclassing by requiring “override”. If the override keyword is present but the superclass doesn’t have a matching method, the compiler warns us about it. Similarly if the superclass implements the same method and the subclass doesn’t include override, we get a warning so that it is clear that you are overriding behavior.
For protocols, I don’t think a required keyword would be the best approach. It’s a completely valid case that a type could conform to a protocol using existing methods, perhaps even from a different module. Further, a single method could satisfy multiple protocols, and be overriden from a superclass. What I would propose would be something like an optional override(<#protocol name#>). Something like the following:
override(RouteDestinationViewController) static func viewController(with url: URL, properties: [String:Any]) -> UIViewController? {
return FooController(properties: properties)
}
A method should be able to include multiple overrides (including a bare override to indicate that it is overriding a class method).
Thoughts? Are you seeing similar issues?
David Beck
http://davidbeck.co
http://twitter.com/davbeck
http://facebook.com/davbeck
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160916/8a69d47c/attachment.html>
More information about the swift-evolution
mailing list