[Pitch] Requiring proactive overrides for default protocol implementations.

Inline

Regards
(From mobile)

From the Swift Programming Language: 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.

I would like to extend this cautious approach to protocols, forcing the developer to deliberately override an implementation that’s inherited from a protocol extension. This would prevent accidental overrides and force the user to proactively choose to implement a version of a protocol member that already exists in the protocol extension.

I envision this as using the same `override` keyword that’s used in class based inheritance but extend it to protocol inheritance:

protocol A {
    func foo()
}

extension A {
    func foo() { .. default implementation … }
}

type B: A {

    override required func foo () { … overrides implementation … }
}

A couple questions about your pitch:

1) What is “required” doing there?

I threw it in not because I’m tied to it but because I wanted it to be part of the conversation.
This is a requirement from conforming to the protocol.

2) Is “override” only required when there is a default implementation of the protocol requirement, or is it required whenever you are implementing a protocol requirement?

Override is only because it is overriding the default implementation of the protocol requirement. Without that default implementation there would be no override, it would simply be satisfying the requirement.

  * If the former, it might be the case that it’s too easy to forget to add the “override” keyword (because it’s needed for some implementations of protocol requirements but not others), which undercuts the value of having it.

Forcing the override keyword makes it clear at the definition point that the story extends beyond the method or whatever to point to a default implementation that is being replaced. I *really* like having that reference in terms of both code construction (“I am doing this as a deliberate act”) with the compiler complaining otherwise, and in terms of code self documentation (“I know this was added deliberately, what default did it override?”)

  * If the latter, “override” is probably the wrong keyword because it’s not overriding anything in the common case of implementing a non-defaulted requirement.

It would be pointless if it’s just satisfying a requirement. That’s why introduced both keywords into the discussion. (And because I’m still being influenced by the “near miss” conversation.)

One could always argue that should protocol definitions ever be allowed to contain default implementations ala-java default methods,

I fully expect this will happen someday. It would have happened when protocol extensions were introduced except that the implementation was a bit more involved than we had time for.

the distinction between former and latter would go away, and it would be happy anticipation to have mandated *override* all along in all cases, ensuring that future default methods would not accidentally take precedence of current code or wind up being treated differently than other overrides.

Please spell out the scenario you are talking about.

  - Doug

···

On Apr 27, 2016, at 12:45 PM, L. Mihalkovic <laurent.mihalkovic@gmail.com> wrote:
On Apr 27, 2016, at 9:31 PM, Erica Sadun via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Apr 27, 2016, at 12:25 PM, Douglas Gregor <dgregor@apple.com <mailto:dgregor@apple.com>> wrote:

On Apr 27, 2016, at 10:10 AM, Erica Sadun <erica@ericasadun.com <mailto:erica@ericasadun.com>> wrote:

2) Is “override” only required when there is a default implementation of the protocol requirement, or is it required whenever you are implementing a protocol requirement?

Override is only because it is overriding the default implementation of the protocol requirement. Without that default implementation there would be no override, it would simply be satisfying the requirement.

For me, this doesn’t provide additional value of “required”: i.e., the value of having a keyword here is in telling me that I failed to implement a requirement when I’ve clearly said that I wanted to implement a requirement. Whether there was a default there or not isn’t really very interesting. Plus, a default could be added later to a requirement that I implement: that change has zero impact on how my code works (before or after), but now I’d be require to add an “override” keyword when I recompile.

Contrast that with classes: if you recompile against a new version of a library and the compiler tells you that you need to add “override”, it’s serious because the semantics of your program will change if you’re now overriding something that you weren’t before.

Consider these situations:

* I use the word 'required' but I use a Double in the signature instead of a Float. Compiler detects. Instant alert on the mismatch.
* I implement a required member but fail to use the word required. Compiler detects. Instant alert: this is a required member, did you intend to use this signature for that purpose?
* I implement a required member. I then later provide a default. Compiler detects. "This version will be overridden by the default version the protocol and/or extension. Either remove this implementation or add the override keyword to prefer it to the default version."
* I implement a default version and then later implement the required member. Compiler detects Same warning as above.

  * If the former, it might be the case that it’s too easy to forget to add the “override” keyword (because it’s needed for some implementations of protocol requirements but not others), which undercuts the value of having it.

Forcing the override keyword makes it clear at the definition point that the story extends beyond the method or whatever to point to a default implementation that is being replaced. I *really* like having that reference in terms of both code construction (“I am doing this as a deliberate act”) with the compiler complaining otherwise, and in terms of code self documentation (“I know this was added deliberately, what default did it override?”)

I see the former (“I am doing this as a deliberate act”) as a very common complaint; the latter not nearly as much. What motivates that? And does it justify adding a *second* keyword to these declarations?

I think I caught the gist in the situations above. If not, will respond further.

I’d also like to bring up two related topics, although they probably should at some point move to their own thread if they have any legs:

Related topic 1: How should a consumer handle a situation where two unrelated protocols both require the same member and offer different default implementations. Can they specify which implementation to accept or somehow run both?

type B: A, C {
    override required func foo() { A.foo(); C.foo() }
}

I think the right answer here is for the compiler to produce an ambiguity if you don’t implement the requirement yourself, and then solving your “related topic 2” lets you choose which implementation you want.

How do you choose which one? What syntax? For example:

required func foo = A.foo

would be the simplest approach

type B: A, C {
  override required func foo() { A.foo(self)() }
}

+1

Related topic 2: How can a consumer “inherit” the behavior of the default implementation (like calling super.foo() in classes) and then extend that behavior further. This is a bit similar to how the initialization chaining works. I’d like to be able to call A.foo() and then add custom follow-on behavior rather than entirely replacing the behavior.

type B: A {
    override required func foo() { A.foo(); … my custom behavior … }
}

Seems totally reasonable to me. One ugly syntax: A.foo(self)(), leveraging the currying of self?

Ugly but it would pretty much do it for me. It offers an expressive way to say “Please execute the A.foo behavior using the self instance”. Does 3 still support this?

Probably not? I actually don’t know ;)

I vaguely remember some stuff being changed. I'd normally try to test but I can't get a dev build to work in Xcode since the March 24 build. :(

-- E

···

On Apr 27, 2016, at 6:03 PM, Douglas Gregor <dgregor@apple.com> wrote:

... so *override* seems like the right keyword choice for today, that would be future proof in case default methods ever make it in protocols (which might be a cheap partial answer to the 'what about mixins' question)

···

On Apr 27, 2016, at 9:56 PM, Erica Sadun <erica@ericasadun.com> wrote:

On Apr 27, 2016, at 1:45 PM, L. Mihalkovic <laurent.mihalkovic@gmail.com> wrote:

Inline

Regards
(From mobile)

On Apr 27, 2016, at 9:31 PM, Erica Sadun via swift-evolution <swift-evolution@swift.org> wrote:

On Apr 27, 2016, at 12:25 PM, Douglas Gregor <dgregor@apple.com> wrote:

On Apr 27, 20

  * If the latter, “override” is probably the wrong keyword because it’s not overriding anything in the common case of implementing a non-defaulted requirement.

It would be pointless if it’s just satisfying a requirement. That’s why introduced both keywords into the discussion. (And because I’m still being influenced by the “near miss” conversation.)

One could always argue that should protocol definitions ever be allowed to contain default implementations ala-java default methods, the distinction between former and latter would go away, and it would be happy anticipation to have mandated *override* all along in all cases, ensuring that future default methods would not accidentally take precedence of current code or wind up being treated differently than other overrides.

I would expect default implementations in protocol definitions to act exactly like protocol definitions in extensions from the Type point of view.

From the protocol point of view, I would introduce the same override behavior to signal affirmative intent.

Draft. Criticism and suggestions both welcome. -- E

Requiring Proactive Overrides for Default Protocol Implementations

Proposal: tbd
Author(s): Erica Sadun <http://github.com/erica&gt;
Status: tbd
Review manager: tbd
<Requiring Proactive Overrides for Default Protocol Implementations · GitHub

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&gt; thread

<Requiring Proactive Overrides for Default Protocol Implementations · GitHub

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.

<Requiring Proactive Overrides for Default Protocol Implementations · GitHub 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.
<Requiring Proactive Overrides for Default Protocol Implementations · GitHub 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
}
<Requiring Proactive Overrides for Default Protocol Implementations · GitHub 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.
}
<Requiring Proactive Overrides for Default Protocol Implementations · GitHub 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
<Requiring Proactive Overrides for Default Protocol Implementations · GitHub 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.

<Requiring Proactive Overrides for Default Protocol Implementations · GitHub 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.

<Requiring Proactive Overrides for Default Protocol Implementations · GitHub Considered

Not at this time.

<Requiring Proactive Overrides for Default Protocol Implementations · GitHub and Thanks

Thanks, Doug Gregor, Jordan Rose, and Joe Groff

···

On Apr 27, 2016, at 6:07 PM, Douglas Gregor <dgregor@apple.com> wrote:

Great proposal, I think it will clear up some mistakes. What happens when
it is only an override sometimes? For example:

protocol A {
    associatedtype Element
    func get() -> Element
}

extension A where Element: ArrayLiteralConvertible {
    func get() -> Element { return }
}

struct Example<T> {
    func get() -> T
}

Example does "override", but not always. I'm sorry, I couldn't think of a
good solution to this.

···

On Thursday, 28 April 2016, L. Mihalkovic via swift-evolution < swift-evolution@swift.org> wrote:

On Apr 27, 2016, at 9:56 PM, Erica Sadun <erica@ericasadun.com > <javascript:_e(%7B%7D,'cvml','erica@ericasadun.com');>> wrote:

On Apr 27, 2016, at 1:45 PM, L. Mihalkovic <laurent.mihalkovic@gmail.com > <javascript:_e(%7B%7D,'cvml','laurent.mihalkovic@gmail.com');>> wrote:

Inline

Regards
(From mobile)

On Apr 27, 2016, at 9:31 PM, Erica Sadun via swift-evolution < > swift-evolution@swift.org > <javascript:_e(%7B%7D,'cvml','swift-evolution@swift.org');>> wrote:

On Apr 27, 2016, at 12:25 PM, Douglas Gregor <dgregor@apple.com > <javascript:_e(%7B%7D,'cvml','dgregor@apple.com');>> wrote:

On Apr 27, 20

* If the latter, “override” is probably the wrong keyword because it’s not
overriding anything in the common case of implementing a non-defaulted
requirement.

It would be pointless if it’s just satisfying a requirement. That’s why
introduced both keywords into the discussion. (And because I’m still being
influenced by the “near miss” conversation.)

One could always argue that should protocol definitions ever be allowed to
contain default implementations ala-java default methods, the distinction
between former and latter would go away, and it would be happy anticipation
to have mandated *override* all along in all cases, ensuring that future
default methods would not accidentally take precedence of current code or
wind up being treated differently than other overrides.

I would expect default implementations in protocol definitions to act
exactly like protocol definitions in extensions from the Type point of view.

From the protocol point of view, I would introduce the same override
behavior to signal affirmative intent.

... so *override* seems like the right keyword choice for today, that
would be future proof in case default methods ever make it in protocols
(which might be a cheap partial answer to the 'what about mixins' question)

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@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&gt;
   - Status: tbd
   - Review manager: tbd

<Requiring Proactive Overrides for Default Protocol Implementations · GitHub;
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&gt; thread*
<Requiring Proactive Overrides for Default Protocol Implementations · GitHub;
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.

<Requiring Proactive Overrides for Default Protocol Implementations · GitHub
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.

<Requiring Proactive Overrides for Default Protocol Implementations · GitHub
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
}

<Requiring Proactive Overrides for Default Protocol Implementations · GitHub
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.
}

<Requiring Proactive Overrides for Default Protocol Implementations · GitHub
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
<Requiring Proactive Overrides for Default Protocol Implementations · GitHub
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.

<Requiring Proactive Overrides for Default Protocol Implementations · GitHub
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.

<Requiring Proactive Overrides for Default Protocol Implementations · GitHub
Considered

Not at this time.

<Requiring Proactive Overrides for Default Protocol Implementations · GitHub
and Thanks
Thanks, Doug Gregor, Jordan Rose, and Joe Groff

On Apr 27, 2016, at 6:07 PM, Douglas Gregor <dgregor@apple.com> wrote:

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Hi, Erica. Sorry for not participating in the first round here. I’m…not so happy with this direction, for a number of reasons. (I apologize for the laundry list, but they’re not really related complaints.)

- ‘required’ already means something today: it means “this initializer must be present on all subclasses”. The reason it only applies to initializers is because all other members are always present on all subclasses.

(Counter-argument: using ‘required’ on an initializer could be seen as making an implicit protocol, just for that class hierarchy.)

- ‘override’ likewise already has a meaning; allowing ‘override’ to be satisfied by a protocol requirement means that it might miss an override intended for a superclass—or inadvertently become one when an SDK is updated.

(Counter-argument: that last can happen to protocols already.)

- This doesn’t cover cases where methods in one protocol extension satisfy requirements in another.

- This doesn’t cover retroactive modeling.

- I’m not sure what it means to "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)”. Protocol conformance is decided at compile time; there won’t ever be any members in type extensions that take precedent over a type declaration without causing a conflict. (That is, currently you are not allowed to define such a member.)

- A member in the type does not “override" a member in a protocol extension today, because such a call is not dynamically dispatched. Making protocol extension members dynamically dispatched is challenging at the least and would require an implementation plan in the proposal.

- Thank you for writing up all of the source compatibility cases! I think there’s no issue with binary compatibility, since IIUC the proposal doesn’t change how anything is implemented, and we think we know how to handle binary compatibility there. But I’d like to think about it a little more.

- The “A.foo(self)()” syntax is clever, but it doesn’t work correctly for mutating methods (because you can’t curry an inout). On the other hand, JoeG already brought up the idea of making ‘self’ the first argument of the implicit static member. It still doesn’t solve the problem of picking a protocol extension, but that’s not new. (This isn’t a complaint, I guess, just a note.)

I’m not sure I have a meaningful summary or conclusion, but I’d be hesitant to do all of this without these concerns being addressed.

Jordan

···

On Apr 28, 2016, at 09:53, Erica Sadun <erica@ericasadun.com> 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&gt;
Status: tbd
Review manager: tbd
<Requiring Proactive Overrides for Default Protocol Implementations · GitHub

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&gt; thread

<Requiring Proactive Overrides for Default Protocol Implementations · GitHub

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.

<Requiring Proactive Overrides for Default Protocol Implementations · GitHub 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.
<Requiring Proactive Overrides for Default Protocol Implementations · GitHub 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
}
<Requiring Proactive Overrides for Default Protocol Implementations · GitHub 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.
}
<Requiring Proactive Overrides for Default Protocol Implementations · GitHub 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
<Requiring Proactive Overrides for Default Protocol Implementations · GitHub 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.

<Requiring Proactive Overrides for Default Protocol Implementations · GitHub 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.

<Requiring Proactive Overrides for Default Protocol Implementations · GitHub Considered

Not at this time.

<Requiring Proactive Overrides for Default Protocol Implementations · GitHub and Thanks

Thanks, Doug Gregor, Jordan Rose, and Joe Groff

On Apr 27, 2016, at 6:07 PM, Douglas Gregor <dgregor@apple.com <mailto:dgregor@apple.com>> wrote:

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&gt;
  * Status: tbd
  * Review manager: tbd

    <Requiring Proactive Overrides for Default Protocol Implementations · GitHub

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&gt; thread/

    <Requiring Proactive Overrides for Default Protocol Implementations · GitHub

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.

    <Requiring Proactive Overrides for Default Protocol Implementations · GitHub
    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.

        <Requiring Proactive Overrides for Default Protocol Implementations · GitHub
        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
}

        <Requiring Proactive Overrides for Default Protocol Implementations · GitHub
        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.
}

        <Requiring Proactive Overrides for Default Protocol Implementations · GitHub
        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

        <Requiring Proactive Overrides for Default Protocol Implementations · GitHub
        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.

    <Requiring Proactive Overrides for Default Protocol Implementations · GitHub
    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.

    <Requiring Proactive Overrides for Default Protocol Implementations · GitHub
    Considered

Not at this time.

    <Requiring Proactive Overrides for Default Protocol Implementations · GitHub
    and Thanks

Thanks, Doug Gregor, Jordan Rose, and Joe Groff

On Apr 27, 2016, at 6:07 PM, Douglas Gregor <dgregor@apple.com >> <mailto:dgregor@apple.com>> wrote:

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Hey, what annotations would I have in this case:

Module 1:

Type AType { func foo() { ... } }

Module 2:

import Module1protocol A { func foo() {...default...} }extension AType: A {}

Also, for your *alternatives* section:

protocol A { func foo() {...default...} }Type AType: A {
    func A.foo() {...replacement...}
}

I actually prefer this alternative, I think it fixes many issues.

···

On Thu, Apr 28, 2016 at 12:47 PM, Erica Sadun via swift-evolution < swift-evolution@swift.org> wrote:

On Apr 27, 2016, at 6:03 PM, Douglas Gregor <dgregor@apple.com> wrote:

2) Is “override” only required when there is a default implementation of
the protocol requirement, or is it required whenever you are implementing a
protocol requirement?

Override is only because it is overriding the default implementation of
the protocol requirement. Without that default implementation there would
be no override, it would simply be satisfying the requirement.

For me, this doesn’t provide additional value of “required”: i.e., the
value of having a keyword here is in telling me that I failed to implement
a requirement when I’ve clearly said that I wanted to implement a
requirement. Whether there was a default there or not isn’t really very
interesting. Plus, a default could be added later to a requirement that I
implement: that change has zero impact on how my code works (before or
after), but now I’d be require to add an “override” keyword when I
recompile.

Contrast that with classes: if you recompile against a new version of a
library and the compiler tells you that you need to add “override”, it’s
serious because the semantics of your program will change if you’re now
overriding something that you weren’t before.

Consider these situations:

* I use the word 'required' but I use a Double in the signature instead of
a Float. Compiler detects. Instant alert on the mismatch.
* I implement a required member but fail to use the word required.
Compiler detects. Instant alert: this is a required member, did you intend
to use this signature for that purpose?
* I implement a required member. I then later provide a default. Compiler
detects. "This version will be overridden by the default version the
protocol and/or extension. Either remove this implementation or add the
override keyword to prefer it to the default version."
* I implement a default version and then later implement the required
member. Compiler detects Same warning as above.

* If the former, it might be the case that it’s too easy to forget to add
the “override” keyword (because it’s needed for some implementations of
protocol requirements but not others), which undercuts the value of having
it.

Forcing the override keyword makes it clear at the definition point that
the story extends beyond the method or whatever to point to a default
implementation that is being replaced. I *really* like having that
reference in terms of both code construction (“I am doing this as a
deliberate act”) with the compiler complaining otherwise, and in terms of
code self documentation (“I know this was added deliberately, what default
did it override?”)

I see the former (“I am doing this as a deliberate act”) as a very common
complaint; the latter not nearly as much. What motivates that? And does it
justify adding a *second* keyword to these declarations?

I think I caught the gist in the situations above. If not, will respond
further.

I’d also like to bring up two related topics, although they probably
should at some point move to their own thread if they have any legs:

Related topic 1: How should a consumer handle a situation where two
unrelated protocols both require the same member and offer different
default implementations. Can they specify which implementation to accept or
somehow run both?

type B: A, C {
    override required func foo() { A.foo(); C.foo() }
}

I think the right answer here is for the compiler to produce an ambiguity
if you don’t implement the requirement yourself, and then solving your
“related topic 2” lets you choose which implementation you want.

How do you choose which one? What syntax? For example:

required func foo = A.foo

would be the simplest approach

type B: A, C {
  override required func foo() { A.foo(self)() }
}

+1

Related topic 2: How can a consumer “inherit” the behavior of the default
implementation (like calling super.foo() in classes) and then extend that
behavior further. This is a bit similar to how the initialization chaining
works. I’d like to be able to call A.foo() and then add custom follow-on
behavior rather than entirely replacing the behavior.

type B: A {
    override required func foo() { A.foo(); … my custom behavior … }
}

Seems totally reasonable to me. One ugly syntax: A.foo(self)(), leveraging
the currying of self?

Ugly but it would pretty much do it for me. It offers an expressive way to
say “Please execute the A.foo behavior using the self instance”. Does 3
still support this?

Probably not? I actually don’t know ;)

I vaguely remember some stuff being changed. I'd normally try to test but
I can't get a dev build to work in Xcode since the March 24 build. :(

-- E

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Sorry, I sent too early. Example should have been:

struct Example<T>: A {
    func get() -> T {...}
}

My mistake does bring up another question. What if it only conforms after
the method is defined, in another module?

extension Example: A {}

···

On Thursday, 28 April 2016, Andrew Bennett <cacoyi@gmail.com> wrote:

Great proposal, I think it will clear up some mistakes. What happens when
it is only an override sometimes? For example:

protocol A {
    associatedtype Element
    func get() -> Element
}

extension A where Element: ArrayLiteralConvertible {
    func get() -> Element { return }
}

struct Example<T> {
    func get() -> T
}

Example does "override", but not always. I'm sorry, I couldn't think of a
good solution to this.

On Thursday, 28 April 2016, L. Mihalkovic via swift-evolution < > swift-evolution@swift.org > <javascript:_e(%7B%7D,'cvml','swift-evolution@swift.org');>> wrote:

On Apr 27, 2016, at 9:56 PM, Erica Sadun <erica@ericasadun.com> wrote:

On Apr 27, 2016, at 1:45 PM, L. Mihalkovic <laurent.mihalkovic@gmail.com> >> wrote:

Inline

Regards
(From mobile)

On Apr 27, 2016, at 9:31 PM, Erica Sadun via swift-evolution < >> swift-evolution@swift.org> wrote:

On Apr 27, 2016, at 12:25 PM, Douglas Gregor <dgregor@apple.com> wrote:

On Apr 27, 20

* If the latter, “override” is probably the wrong keyword because it’s
not overriding anything in the common case of implementing a non-defaulted
requirement.

It would be pointless if it’s just satisfying a requirement. That’s why
introduced both keywords into the discussion. (And because I’m still being
influenced by the “near miss” conversation.)

One could always argue that should protocol definitions ever be allowed
to contain default implementations ala-java default methods, the
distinction between former and latter would go away, and it would be happy
anticipation to have mandated *override* all along in all cases, ensuring
that future default methods would not accidentally take precedence of
current code or wind up being treated differently than other overrides.

I would expect default implementations in protocol definitions to act
exactly like protocol definitions in extensions from the Type point of view.

From the protocol point of view, I would introduce the same override
behavior to signal affirmative intent.

... so *override* seems like the right keyword choice for today, that
would be future proof in case default methods ever make it in protocols
(which might be a cheap partial answer to the 'what about mixins' question)

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?

extension NotMyType: ProtocolIdesigned {...}

extension NotMyProtocol {
     required func method1() {...}
     override required func method2() {...} // assumes NMP has already provided default
     func newThing() {...}
}

The only tricky bit is when NotMyProtocol already has a default required func implementation and an override required func implementation (although that should be rare). In such case, you probably have to create a new protocol DerivedProtocol: NotMyProtocol and work from there. The override in the DerivedProtocol will then take priority over the override in NotMyProtocol.

-- E

···

On Apr 28, 2016, at 11:05 AM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

Sorry, that's not my question, which doesn't involve protocols I don't own. Let me restate. Given three types I don't own as follows:

struct A : Frobnicate {
    override required func frobnicate() { print("A") } // "A", or delete to get default
}
struct B: Frobnicate {
    override required func frobnicate() { print("B") } // "B", or delete to get default
}
struct C: Frobnicate  { }

-- E

···

On Apr 28, 2016, at 11:48 AM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

Sorry, that's not my question, which doesn't involve protocols I don't own. Let me restate. Given three types I don't own as follows:

struct A {
    func frobnicate() { print("A") }
}
struct B {
    func frobnicate() { print("B") }
}
struct C { }

I want to conform them to a protocol of my own design, Frobnicatable, and supply a default `frobnicate()`:

protocol Frobnicatable {
    func frobnicate()
}
extension Frobnicatable {
    func frobnicate() { print("Default") }
}
extension A: Frobnicatable { }
extension B: Frobnicatable { }
extension C: Frobnicatable { }

let c = C()
c.frobnicate() // "Default"

(Yes, I realize there are issues regarding static and dynamic dispatch that limit the utility of this particular example--let's leave those aside for now.)
Where would I affix keywords such as `required` and `override` to make this work after implementation of your proposal?

Sorry, that's not my question, which doesn't involve protocols I don't own.
Let me restate. Given three types I don't own as follows:

struct A {
    func frobnicate() { print("A") }
}
struct B {
    func frobnicate() { print("B") }
}
struct C { }

I want to conform them to a protocol of my own design, Frobnicatable, and
supply a default `frobnicate()`:

protocol Frobnicatable {
    func frobnicate()
}
extension Frobnicatable {
    func frobnicate() { print("Default") }
}
extension A: Frobnicatable { }
extension B: Frobnicatable { }
extension C: Frobnicatable { }

let c = C()
c.frobnicate() // "Default"

(Yes, I realize there are issues regarding static and dynamic dispatch that
limit the utility of this particular example--let's leave those aside for
now.)
Where would I affix keywords such as `required` and `override` to make this
work after implementation of your proposal?

···

On Thu, Apr 28, 2016 at 12:25 PM, Erica Sadun <erica@ericasadun.com> wrote:

>
> On Apr 28, 2016, at 11:05 AM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:
>
> 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?

extension NotMyType: ProtocolIdesigned {...}

extension NotMyProtocol {
     required func method1() {...}
     override required func method2() {...} // assumes NMP has already
provided default
     func newThing() {...}
}

The only tricky bit is when NotMyProtocol already has a default required
func implementation and an override required func implementation (although
that should be rare). In such case, you probably have to create a new
protocol DerivedProtocol: NotMyProtocol and work from there. The override
in the DerivedProtocol will then take priority over the override in
NotMyProtocol.

I'm glad you brought this up and provided a clear example Xiaodi.

Erica, as I mentioned a few days ago (and Dave A gave +1) this proposal cannot break retroactive modeling if it is going to fly. Can you please update it to clarify how you envision it interacts with retroactive modeling? Would these new keywords only be required when the conformance is declared in the same module as the method?

···

Sent from my iPad

On Apr 28, 2016, at 12:48 PM, Xiaodi Wu via swift-evolution <swift-evolution@swift.org> wrote:

On Thu, Apr 28, 2016 at 12:25 PM, Erica Sadun <erica@ericasadun.com> wrote:
>
> On Apr 28, 2016, at 11:05 AM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:
>
> 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?

extension NotMyType: ProtocolIdesigned {...}

extension NotMyProtocol {
     required func method1() {...}
     override required func method2() {...} // assumes NMP has already provided default
     func newThing() {...}
}

The only tricky bit is when NotMyProtocol already has a default required func implementation and an override required func implementation (although that should be rare). In such case, you probably have to create a new protocol DerivedProtocol: NotMyProtocol and work from there. The override in the DerivedProtocol will then take priority over the override in NotMyProtocol.

Sorry, that's not my question, which doesn't involve protocols I don't own. Let me restate. Given three types I don't own as follows:

struct A {
    func frobnicate() { print("A") }
}
struct B {
    func frobnicate() { print("B") }
}
struct C { }

I want to conform them to a protocol of my own design, Frobnicatable, and supply a default `frobnicate()`:

protocol Frobnicatable {
    func frobnicate()
}
extension Frobnicatable {
    func frobnicate() { print("Default") }
}
extension A: Frobnicatable { }
extension B: Frobnicatable { }
extension C: Frobnicatable { }

let c = C()
c.frobnicate() // "Default"

(Yes, I realize there are issues regarding static and dynamic dispatch that limit the utility of this particular example--let's leave those aside for now.)
Where would I affix keywords such as `required` and `override` to make this work after implementation of your proposal?

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Sorry, that's not my question, which doesn't involve protocols I don't own. Let me restate. Given three types I don't own as follows:

struct A : Frobnicate {
    override required func frobnicate() { print("A") } // "A", or delete to get default
}
struct B: Frobnicate {
    override required func frobnicate() { print("B") } // "B", or delete to get default
}
struct C: Frobnicate  { }

We can't add the keywords if the structs are defined in a module we import but don't own. We are only declaring the conformance retroactively. The ability to do this is a crucial aspect of generic programming. It isn't yet clear how your proposal handles retroactive modeling.

···

Sent from my iPad

On Apr 28, 2016, at 1:09 PM, Erica Sadun via swift-evolution <swift-evolution@swift.org> wrote:

-- E

On Apr 28, 2016, at 11:48 AM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

Sorry, that's not my question, which doesn't involve protocols I don't own. Let me restate. Given three types I don't own as follows:

struct A {
    func frobnicate() { print("A") }
}
struct B {
    func frobnicate() { print("B") }
}
struct C { }

I want to conform them to a protocol of my own design, Frobnicatable, and supply a default `frobnicate()`:

protocol Frobnicatable {
    func frobnicate()
}
extension Frobnicatable {
    func frobnicate() { print("Default") }
}
extension A: Frobnicatable { }
extension B: Frobnicatable { }
extension C: Frobnicatable { }

let c = C()
c.frobnicate() // "Default"

(Yes, I realize there are issues regarding static and dynamic dispatch that limit the utility of this particular example--let's leave those aside for now.)
Where would I affix keywords such as `required` and `override` to make this work after implementation of your proposal?

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Right, sorry, I should have clarified. The scenario to be supported here is
that the code for structs A, B, and C cannot be modified. They could be
part of the stdlib, for example, or a closed-source third-party library.

···

On Thu, Apr 28, 2016 at 1:18 PM, Matthew Johnson <matthew@anandabits.com> wrote:

Sent from my iPad

On Apr 28, 2016, at 1:09 PM, Erica Sadun via swift-evolution < > swift-evolution@swift.org> wrote:

Sorry, that's not my question, which doesn't involve protocols I don't
own. Let me restate. Given three types I don't own as follows:

struct A : Frobnicate {
    override required func frobnicate() { print("A") } // "A", or delete
to get default
}
struct B: Frobnicate {
    override required func frobnicate() { print("B") } // "B", or delete
to get default
}
struct C: Frobnicate  { }

We can't add the keywords if the structs are defined in a module we import
but don't own. We are only declaring the conformance retroactively. The
ability to do this is a crucial aspect of generic programming. It isn't
yet clear how your proposal handles retroactive modeling.

-- E

On Apr 28, 2016, at 11:48 AM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

Sorry, that's not my question, which doesn't involve protocols I don't
own. Let me restate. Given three types I don't own as follows:

struct A {
    func frobnicate() { print("A") }
}
struct B {
    func frobnicate() { print("B") }
}
struct C { }

I want to conform them to a protocol of my own design, Frobnicatable, and
supply a default `frobnicate()`:

protocol Frobnicatable {
    func frobnicate()
}
extension Frobnicatable {
    func frobnicate() { print("Default") }
}
extension A: Frobnicatable { }
extension B: Frobnicatable { }
extension C: Frobnicatable { }

let c = C()
c.frobnicate() // "Default"

(Yes, I realize there are issues regarding static and dynamic dispatch
that limit the utility of this particular example--let's leave those aside
for now.)
Where would I affix keywords such as `required` and `override` to make
this work after implementation of your proposal?

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

These are compile-time checks and should not affect compiled code.

-- E

···

On Apr 28, 2016, at 12:18 PM, Matthew Johnson <matthew@anandabits.com> wrote:
We can't add the keywords if the structs are defined in a module we import but don't own. We are only declaring the conformance retroactively. The ability to do this is a crucial aspect of generic programming. It isn't yet clear how your proposal handles retroactive modeling.

We can't add the keywords if the structs are defined in a module we import but don't own. We are only declaring the conformance retroactively. The ability to do this is a crucial aspect of generic programming. It isn't yet clear how your proposal handles retroactive modeling.

These are compile-time checks and should not affect compiled code.

Does that mean the conformance declaration will be accepted by the compiler under your proposal? I would really like to see this called out explicitly in the proposal.

···

Sent from my iPad

On Apr 28, 2016, at 5:49 PM, Erica Sadun <erica@ericasadun.com> wrote:

On Apr 28, 2016, at 12:18 PM, Matthew Johnson <matthew@anandabits.com> wrote:

-- E

Hey, what annotations would I have in this case:

Module 1:
Type AType { func foo() { ... } }
Module 2:
import Module1
protocol A { func foo() {...default...} }
extension AType: A {}

No annotations. AType's implementation of foo is unrelated to its conformance, which is satisfied by its existing foo method.

Also, for your alternatives section:

protocol A { func foo() {...default...} }
Type AType: A {
    func A.foo() {...replacement...}
}

I actually prefer this alternative, I think it fixes many issues.

Protocol default implementations do not yet exist.

In this second, you're suggesting instead of doing "override required", you use a naming approach that ties the implementation the specific protocol. I'm not really won over by this approach:

* It does clarify why the method is included
* It does not clarify that the method overrides an existing implementation.
* It could be more easily confused when members are required by multiple protocols.

-- E

···

On Apr 28, 2016, at 6:44 PM, Andrew Bennett <cacoyi@gmail.com> wrote:

[resending without quoting the proposal, because apparently that made Mail emit garbage today]

Hi, Erica. Sorry for not participating in the first round here. I’m…not so happy with this direction, for a number of reasons. (I apologize for the laundry list, but they’re not really related complaints.)

- ‘required’ already means something today: it means “this initializer must be present on all subclasses”. The reason it only applies to initializers is because all other members are always present on all subclasses.

(Counter-argument: using ‘required’ on an initializer could be seen as making an implicit protocol, just for that class hierarchy.)

- ‘override’ likewise already has a meaning; allowing ‘override’ to be satisfied by a protocol requirement means that it might miss an override intended for a superclass—or inadvertently become one when an SDK is updated.

(Counter-argument: that last can happen to protocols already.)

- This doesn’t cover cases where methods in one protocol extension satisfy requirements in another.

- This doesn’t cover retroactive modeling.

- I’m not sure what it means to "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)”. Protocol conformance is decided at compile time; there won’t ever be any members in type extensions that take precedent over a type declaration without causing a conflict. (That is, currently you are not allowed to define such a member.)

- A member in the type does not “override" a member in a protocol extension today, because such a call is not dynamically dispatched. Making protocol extension members dynamically dispatched is challenging at the least and would require an implementation plan in the proposal.

- Thank you for writing up all of the source compatibility cases! I think there’s no issue with binary compatibility, since IIUC the proposal doesn’t change how anything is implemented, and we think we know how to handle binary compatibility there. But I’d like to think about it a little more.

- The “A.foo(self)()” syntax is clever, but it doesn’t work correctly for mutating methods (because you can’t curry an inout). On the other hand, JoeG already brought up the idea of making ‘self’ the first argument of the implicit static member. It still doesn’t solve the problem of picking a protocol extension, but that’s not new. (This isn’t a complaint, I guess, just a note.)

I’m not sure I have a meaningful summary or conclusion, but I’d be hesitant to do all of this without these concerns being addressed.

Jordan