Erica,
In general I fully support this proposal. IMO Swift should be more explicit on what method in class/struct is required by protocol and if it overrides default implementation in protocol extension.

Actually, personally I like the idea that we need even separate base class inheritance declaration and protocol conformance like in Java: class A:B implements C {..} or class A:B::C {}.. or even specify which protocol exactly requires this method like
func f() requiredBy SomeProto {} ...
but never mind :-)

Also your proposal should protect from such situations:
1. We use some 3rd party class AClass that implements AProtocol
2. We write extension to AProtocol, added new method ANewMethod
3. Then, we update the source of that AClass, and in new version of it the same ANewMethod was introduced(like in our AProtocol) 4. Now we have methods with same name in AClass and in protocol extension without any error/warning

Small fix(I think):
-----
protocol A..
protocol B..
extension A { override required func foo() {...A extension...} }
Type CType: A, B {}
-----
>>> don't you want to write just 'required' here, not 'override required' ?


Right now we have protocol extension's priority over type definition:
------------
protocol A {}

class C:A {
    func y() { print("Y in C") }
}

extension A { func y() {print("Y in A")} }

var c : A = C()
c.y() // Y in A here
-----------
so, it seems like you need to add this to "Impact on Existing Code"
I.e. now, when someone declared an protocol extension, it will get this method in class instance. Your proposal says we'll have class ext -> class-> protocol ex. -> protocol. Or I missed something?

Also, can't we just use 'override' instead of 'required'?
I.e. in protocol extension 'override' means - implements something, that was declared already in protocol. In class methods declaration 'override' will mean 'overrides base class'es implementation, or method in protocol extension, or implements protocol requirement'. I don't see the clear need of 'required' keyword here. I mean for me just 'override' will say 'this method is already declared somewhere'.

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: 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 |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 <[email protected]
<mailto:[email protected]>> wrote:



_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to