[swift-evolution] [Pitch] Requiring proactive overrides for default protocol implementations.

Xiaodi Wu xiaodi.wu at gmail.com
Thu Apr 28 12:05:28 CDT 2016

How is retroactive modeling accommodated in this scheme? Say I want to
conform three types I don't own to a protocol of my design and supply a
default implementation for a protocol requirement. How would I go about it?
On Thu, Apr 28, 2016 at 11:53 Erica Sadun via swift-evolution <
swift-evolution at swift.org> wrote:

> Draft. Criticism and suggestions both welcome. -- E
> Requiring Proactive Overrides for Default Protocol Implementations
>    - Proposal: tbd
>    - Author(s): Erica Sadun <http://github.com/erica>
>    - Status: tbd
>    - Review manager: tbd
> <https://gist.github.com/erica/fc66e6f6335750d737e5512797e8284a#introduction>
> Introduction
> This proposal enhances protocol implementation safety. It incorporates two
> keywords that cooperate with compiler checks to limit "near miss"
> implementation errors and accidental member overrides.
> *This proposal was discussed on the Swift Evolution list in the [Pitch]
> Requiring proactive overrides for default protocol implementations.
> <http://thread.gmane.org/gmane.comp.lang.swift.evolution/15496> thread*
> <https://gist.github.com/erica/fc66e6f6335750d737e5512797e8284a#motivation>
> Motivation
> The proposal introduces a mandatory required keyword that marks members
> as fulfiling protocol requirements. This expansion reduces the risk of
> near-miss implementations (for example, adding thud(x: Double) when thud(x:
> Float)is required), provides in-line documentation of why the member has
> been included, thereby enhancing the code-level documentation at the
> implementation point, and supports compile-time checks for protocol
> conformance.
> This proposal extends the override keyword to protocol conformance. The
> Swift Programming Language describes the way subclass methods must override
> implementations established in superclasses. *Methods on a subclass that
> override the superclass’s implementation are marked with **override**—overriding
> a method by accident, without override, is detected by the compiler as an
> error. The compiler also detects methods with override that don’t actually
> override any method in the superclass.*
> Adding an override requirement expands this cautious approach to
> protocols. Developers must override implementations inherited from protocol
> extensions with the override keyword. And the compiler will flag uses of
> override where member implementations do not, in fact, override an
> existing implementation. The keyword prevents accidental overrides, where a
> sensible member name conflicts with signatures established in the protocol
> conformance and forces users to proactively select a version in favor of
> existing protocol extensions.
> <https://gist.github.com/erica/fc66e6f6335750d737e5512797e8284a#detail-design>Detail
> Design
>    - The override keyword is extended to protocol inheritance, and when
>    used prefers the overridden behavior to the default behavior.
>    - Swift will prefer an overridden implementation in preference in
>    reverse hierarchical order: type extensions take precedence over type
>    declarations over protocol extensions over protocol declarations (assuming
>    protocol declarations eventually adopt default implementations).
>    - The required keyword marks a member as satisfying a protocol
>    requirement, whether in protocol extensions, type declarations, or type
>    extensions.
> <https://gist.github.com/erica/fc66e6f6335750d737e5512797e8284a#required-protocol-members>Required
> Protocol Members
> Protocol requirements are marked with required for compile-time checks of
> intentional conformance.
> protocol A {
>     func foo()
>     func bar()
>     func blort()
>     func gar()
> }
> extension A {
>     required func blort() {} // Correct, required by `A`
>     func womble() {} // Correct, new method in extension
>     func gar() {} // Incorrect: Compiler says: add `required` keyword or remove implementation
> }
> struct B: A {
>     required func foo() {} // Correct
>     required func far() {} // Near miss. Compiler: rename method or drop required keyword
>     func bar() {} // Possible accidental name match. Compiler: rename method or add required keyword
> }
> <https://gist.github.com/erica/fc66e6f6335750d737e5512797e8284a#member-overrides>Member
> Overrides
> Overrides are marked with override to ensure intent.
> protocol A {
>     func foo()
>     func bar()
>     func blort()
>     func gar()
> }
> extension A {
>     required func foo() {} // correct
>     func womble() {} // correct
> }
> struct B: A {
>     required func bar() {} // correct
>     required func foo() {} // incorrect: Compiler says: add `override` keyword or remove implementation
>      func womble() {} // incorrect: Compiler says add `override` keyword or remove implementation. `required` is not needed as `womble` is not a required protocol member.
> }
> <https://gist.github.com/erica/fc66e6f6335750d737e5512797e8284a#handling-changes>Handling
> Changes
> Default implementations can be added or removed at any time, as can type
> conformance implementations:
> **Original** **Change** **Outcome**
> Some member implemented in type Protocol adds that member Must add
> `required` to type implementation or rename member to avoid conflict
> Some member implemented in type, marked as `required` Protocol removes
> that member or it never existed Must remove `required` from type
> implementation
> Some member implemented in type, marked as `override` Protocol extension
> removes that member or it never existed Must remove `override` from type
> implementation
> Some member implemented in typed, member not mentioned in protocol Extension
> adds default version of member Type implementation must add `override`
> keyword
> `required` member implemented in type Default member added Must add
> `override` or remove type implementation
> `override required` member implemented in type Remove default member Must
> remove `override` in type implementation
> `override required` member implemented in type Remove type member
> implementation Default implementation now used
> Type member uses `required` keyword Protocol removes requirement or never
> had it Type implementation must remove `required` keyword
> Protocol declares required member Extension implements default
> implementation Extension must add `required` keyword, differentiating
> default implementations from added behavior
> Swift adds default implementations to protocols as well as extensions Protocol
> adds default implementation Type implementation must use both `required`
> and `override` keywords. Protocol extension must use `override` keyword.
> Order of preference goes: overriden member, overriden extension, protocol
> default implementation
> <https://gist.github.com/erica/fc66e6f6335750d737e5512797e8284a#multiple-conformance-conflict>Multiple
> Conformance Conflict
> Consider the following situation. For the sake of future-proofing, this
> example includes default protocol implementations although they do not yet
> exist in Swift.
> protocol A { func foo() {...default...} }protocol B { func foo() {...default...} }extension A { override required func foo() {...A extension...} }Type CType: A, B {}
> In this example, the compiler emits a warning that "CType cannot
> unambiguously differentiate which version of foo to use for CType instances".
> If the CType type were to be removed or either of its conformances erased,
> there would be no compiler issues.
> To fix this scenario, CType must implement a version of foo that resolves
> the conflict:
> Type CType: A, B { override required func foo() {
>     // either
>     A.foo(self)() // uses the A extension default implementation
>     // or
>     B.foo(self)() // uses the B protocol default implementation
>     // or both, one after the other, etc.
> }
> In this rewrite, foo is unambiguously referenced for CType instance
> members.
> <https://gist.github.com/erica/fc66e6f6335750d737e5512797e8284a#impact-on-existing-code>Impact
> on Existing Code
> These changes introduce mandates that do not exist in today's Swift code
> and will require migration. The migrator (and compiler) must detect both
> scenarios: that a member satisfies a protocol requirement and needs the
> required keyword, and that a member overrides a default implementation
> (in current Swift, only in extensions) and needs the overridekeyword.
> In the degenerate case that protocol extensions provide two distinct
> default implementations of the same member (whether required or not), the
> override version should always be preferred. When multiple override versions
> exist, the compiler should emit a warning about ambiguous resolution.
> Using type currying, e.g. A.foo(self) should always resolve using the
> rules enumerated earlier in this proposal, moving from type extensions to
> types to protocol extension to protocols.
> <https://gist.github.com/erica/fc66e6f6335750d737e5512797e8284a#alternatives-considered>Alternatives
> Considered
> Not at this time.
> <https://gist.github.com/erica/fc66e6f6335750d737e5512797e8284a#acknowledgements-and-thanks>Acknowledgements
> and Thanks
> Thanks, Doug Gregor, Jordan Rose, and Joe Groff
> On Apr 27, 2016, at 6:07 PM, Douglas Gregor <dgregor at apple.com> wrote:
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160428/81b64810/attachment.html>

More information about the swift-evolution mailing list