[swift-evolution] Keyword for protocol conformance

Charles Srstka cocoadev at charlessoft.com
Fri Aug 26 14:29:11 CDT 2016


> On Aug 26, 2016, at 1:45 PM, Xiaodi Wu <xiaodi.wu at gmail.com> wrote:
> 
> On Fri, Aug 26, 2016 at 1:27 PM, Charles Srstka <cocoadev at charlessoft.com <mailto:cocoadev at charlessoft.com>> wrote:
>> On Aug 26, 2016, at 11:02 AM, Xiaodi Wu <xiaodi.wu at gmail.com <mailto:xiaodi.wu at gmail.com>> wrote:
>> 
>> Really? I wasn't aware that you could work around the `override` keyword (the one that's required for classes). How do you do that?
> 
> By implementing the subclass’s method before the superclass’s. You can try this yourself:
> 
> - - - Library code: - - -
> 
> open class Superclass {
>     public init() {}
>     public func foo() {
>         print("foo called in library")
>     }
> }
> 
> - - - App code: - - -
> 
> import FooLibrary
> 
> class Subclass: Superclass {
>     func bar() { print("bar called in the app") }
> }
> 
> let obj = Subclass()
> 
> obj.foo()
> 
> - - - output: - - -
> 
> foo called in library
> Program ended with exit code: 0
> 
> - - - - - -
> 
> Now: Change the library code to:
> 
> open class Superclass {
>     public init() {}
>     public func foo() {
>         print("foo called in library")
>         bar()
>     }
>     
>     // Hey look, I didn't even use that stupid new 'open' keyword.
>     public func bar() { print("bar called in library") }
> }
> 
> - - - Run the app again without compiling it, and: - - -
> 
> foo called in library
> bar called in the app
> Program ended with exit code: 0
> 
> - - -
> 
> Voilà: I overrode a method (a supposedly non-overridable one, at that) with no “override” keyword.
> 
> This is clearly a bug in the implementation, not part of the design. Expect it to be fixed as the code for `open` matures. It's certainly not a precedent to be emulated for designing another feature.

It’s a side effect of using straight string equality for conformance, which is the status quo that several proposals here have been hoping to change with protocols.

> Just as File A in your earlier example can implement a protocol method without realizing it, Subclass here has unintentionally overridden a superclass method. This is because ‘override’ does not, to the best of my knowledge, mean anything to the actual machine code that is produced; rather, it signals the developer’s *intent,* thus allowing the compiler to assist in making sure the developer does the right thing.
> 
> I’d actually argue that the example above is a much, much bigger problem than the objection you raised, as it can actually produce unintended behavior at runtime, whereas the example with protocols can’t.
> 
> As for the protocol example, I’d like to refine Option 3 from last night slightly:
> 
> Option 4: A keyword is required on a method declaration if and only if the containing type is declared as conforming to its protocol, either in its definition or in an extension that is visible within the current scope.
> 
> Extensions are not first-class entities and have no visibility of their own.

I didn’t express that very well. Let me clarify what I mean:

internal struct S {}

private protocol P {
    func foo()
}

extension S: P {
    func foo() {}
}

- - - choose “Generated Interface” and you get: - - -

internal struct S {
}


extension S {

    internal func foo()
}

- - -

While the extension is visible, the fact that it adds conformance to P is not. Therefore, as far as code outside this file is concerned, there is no conformance to P.

> In any case, you have not solved the problem, which has nothing to do with whether something is "reasonable to know": when a default implementation A is overridden by implementation B, implementation A may be visible only in a *more restricted* access scope than implementation B. (This is not the case with overriding superclass members in subclasses.) It can be perfectly "reasonable to know" about both A and B, but there is still no way you can indicate this knowledge by appending a keyword to the declaration for implementation B if the access scope for implementation A is unutterable where B is declared.


Could you provide an example of code where this would present a problem?

Charles

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160826/a2c35347/attachment.html>


More information about the swift-evolution mailing list