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

Erica Sadun erica at ericasadun.com
Mon May 9 13:03:20 CDT 2016


The pitch was not warmly received. If you want to pick it up and run with it, go ahead. 
https://gist.github.com/erica/fc66e6f6335750d737e5512797e8284a <https://gist.github.com/erica/fc66e6f6335750d737e5512797e8284a>

I have a running list of dead or deferred ideas here: https://gist.github.com/erica/9eae0d949297509ad86e


-- E

> On May 9, 2016, at 11:49 AM, Vladimir.S <svabox at gmail.com> wrote:
> 
> Hi Erica, could you clarify, what is state of this proposal and your plans regarding it? I believe we certainly should make Swift more explicit regarding what methods in type are required by the conformed protocol and what methods are required(and which are 'optional') in protocol extensions.
> 
> Right now there is a discussion regarding 'optional' keyword("Modify optional method semantics for swift"), and I remembered your proposal..
> 
> Probably 'optional' keyword for non-required methods in extension instead of marking 'required' methods will looks better(as they are optional to the protocol itself), what do you think?
> I.e.
> 
> 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..
> 
>    func blort() {} // Correct, was introduced in `A`
>    optional func womble() {} // Correct, new(optional) method in extension
>    optional func gar() {} // Incorrect: Compiler says: remove `optional`..
> }
> 
> 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
> 
>    func womble() {} // ?? how this method should be 'marked' ??
> }
> 
> (But personally I think one *overload* keyword will do the job in both cases - in extension and in type declaration)
> 
> Regarding this "func womble()" questions.. I think we need *at least* compilation warning that *at the moment of compilation*, B.womble may(?) conflicts with extension of A.womble.
> 
> Personaly I was not expecting to get the result of this code:
> 
> protocol A {
>  func a()
> }
> 
> extension A {
>   func b() { print("(b) in A") }
> }
> 
> struct C : A {
>    func a() {}
>    func b() { print("(b) in C") }
> }
> 
> var c : A = C()
> c.b()  // (b) in A
> 
> 
>> On 28.04.2016 19:53, Erica Sadun via swift-evolution 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: tbd2
>>> 
>>> 
>>> 
>>> <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 |override|keyword.
>>> 
>>> 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
>>>> <mailto: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/20160509/6604e114/attachment.html>


More information about the swift-evolution mailing list