[swift-evolution] [Proposal] clarification around protocol implementation and protocol extensions
david at alkaline-solutions.com
Sat Feb 18 01:07:08 CST 2017
> On Feb 17, 2017, at 10:53 PM, Xiaodi Wu <xiaodi.wu at gmail.com> wrote:
> This draft proposes something that's been discussed on this list several times over the past few years, but now with a different spelling. However, previous objections never centered around the spelling.
> As discussed in previous threads on this topic, any such required keyword breaks retroactive conformance. That is, if I want to conform someone else's type to my protocol, I must edit that person's code if your idea is accepted.
I believe this proposal is different in that it only requires specification for clarity not for behavioral changes, and only requires the keyword to be specified for protocols known at the site of method/property declaration.
> In so doing, this idea rejects an important (essential, IMO) mental model of what protocol conformance entails. Specifically, I conform a type T to a protocol P when I discover, having already implemented T, that it fulfills the semantic and syntactic requirements of P. Unlike subclassing, I'm not setting out with the intention of making a type T that conforms to P; rather, I discover this fact to my great delight after implementation of T. The analogy to subclassing is therefore inaccurate. Notionally, one always inherits from a superclass first, then overrides.
> This is no mere theoretical notion. It is a Swift idiom to state conformance to protocols in an extension. Sometimes, the type will already implement some but not all of the protocol's requirements outside that extension because it is essential to the raison d'être of the type, and only the balance of the requirements would then be implemented in the extension that states conformance. It would be exceedingly unfortunate to forbid this pattern, which is both elegant and expressive, but OTOH it would be strange to have a method declare that it fulfills a requirement of a protocol to which, lexically, it had not yet been conformed.
The declaration is only required on types for protocols which the type is known to implement at the file level. If some other code (even within the same module) extends a type to support a protocol, there is no requirement that previous methods had been documented as fulfilling that new protocol.
In this sense, not every method which is mapped into a protocol may be marked as fulfilling a protocol, but the purpose isn’t to solve every corner case. If that were indeed the purpose, I could propose something much wordier where the extension has to declare that intent to expose existing methods as part of protocol conformance.
> Lastly, it makes a very common task, that of conforming to a protocol, syntactically heavy. This is exacerbated when you consider that the scheme outlined here has the greatest benefit only when conformance to one protocol is concerned. When conforming to more than one protocol, a similar level of compiler help can only be obtained if you allow annotations as to which protocol's requirement is being fulfilled. To implement this additional syntax would be ludicrously heavy, but to ignore the issue would be failing to consider one major aspect of protocols: composability (as opposed to single inheritance). Again here, this is a critical difference from subclassing that makes adapting "override" (regardless of whether you choose a novel spelling) ineffectual.
The purpose isn’t to map methods to protocols, but to clarify that a method exists to meet the requirements of a protocol. Without this, a simple typo (or redefinition of methods such as with the changes in Swift 3’s importer) causes what you thought was conforming to a protocol to either fail, or worse silently change behavior.
> Previous discussions on this topic have agreed that the developer experience of conforming a type to a protocol can be greatly improved, but the consensus has been that requiring a keyword to indicate protocol requirements is not the way to go about it. I too would love to see progress made on this issue, but having been previously an advocate for a solution similar to yours, the views of some very wise people have changed my thinking.
There are often cases for the compiler to guess a developer’s intent to simplify syntax, but in this case I believe people are being bit by the compiler guessing incorrectly. If protocols didn’t make implementation of its requirements optional (via optional methods in objective-c, and protocol extensions in Swift) then there wouldn’t be a need to annotate methods to clarify intent. Given those features, I have trouble imagining a system where a compiler would be able to understand the developer’s intent and prevent issues without tagging protocol implementations in some manner.
Unless I’m incorrect in my assumption that there compiler could only infer developer intent via some sort of method tagging, then it really is a decision whether clarity or terseness is more important in this scenario.
More information about the swift-evolution