[swift-evolution] Keyword for protocol conformance

Xiaodi Wu xiaodi.wu at gmail.com
Fri Aug 26 15:19:07 CDT 2016


On Fri, Aug 26, 2016 at 3:10 PM, Charles Srstka <cocoadev at charlessoft.com>
wrote:

> On Aug 26, 2016, at 3:02 PM, Xiaodi Wu <xiaodi.wu at gmail.com> wrote:
>
>
> On Fri, Aug 26, 2016 at 2:57 PM, Charles Srstka <cocoadev at charlessoft.com>
>  wrote:
>
>> On Aug 26, 2016, at 2:49 PM, Xiaodi Wu <xiaodi.wu at gmail.com> wrote:
>>
>>
>> Sorry, I was referring to my original example: S is in a different file
>> from P and has its own implementation of foo(), and P has its own default
>> implementation of foo(). I assumed you simplified the example above to
>> discuss the generated interface. I didn't realize you were moving on to a
>> different example.
>>
>>
>> You are correct; it was a simplified example to discuss the generated
>> interface. I was confused by your objection’s proximity to it; sorry for
>> the noise.
>>
>>
>>>> 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?
>>>>
>>>
>>> I'm still talking about the same example. How do you rationalize your
>>> statement that no keyword is needed because it's not "reasonable to know"
>>> about both S and P when compiling the file in which P is declared?
>>>
>>>
>>> When compiling the file in which P is declared, you would add the
>>> keyword. Code outside this file that happened to define methods named foo()
>>> would not, since they would not be consciously conforming to the protocol.
>>>
>>
>> What keyword could you add to P, when the overriding member is in S?
>>
>> File A:
>> ```
>> internal struct S {
>>   func foo() { }
>> }
>> ```
>>
>> File B:
>> ```
>> private protocol P {
>>   func foo()
>> }
>>
>> extension P {
>>   func foo() { }
>> }
>>
>> extension S : P { }
>> ```
>>
>> Where do I append your proposed keyword? Or, how do you rationalize its
>> not being required on the basis of "reasonable to know"?
>>
>>
>> File A does not need the keyword, since it is not implementing P by
>> adding foo() and cannot be expected to know about it, and thus it’s rather
>> arguable to say that it is “overriding” anything. The extension that
>> conforms S to P declares no methods, so it is clear that this is meant to
>> be retroactively conforming, so I am not convinced a keyword is needed
>> here. However, there is room for debate here, and if we determined that a
>> keyword should be required, then I would say it should go in the extension
>> that conforms S to P, since that is where the “problem” occurs.
>>
>> If S had been declared in File B, however, there would be a keyword
>> attached to its declaration of foo(), since the information that S conforms
>> to P, as well as the fact that foo() is a requirement of said protocol,
>> would all be visible in the current scope.
>>
>
> Why? S.foo() is visible throughout the module, but outside this file,
> S.foo() doesn't override anything. Why should it be marked as an `override`
> when, as you say, the generated interface shows no sign of conformance to P?
> In addition, how would you justify a requirement to fiddle with these
> keywords when someone simply refactors an internally visible type with no
> private members from one file to another? Your proposed rule just broke
> copy-and-paste...
>
>
> Because it indicates the programmer’s *intent.* If the protocol is visible
> at the time you’re writing the declaration for S.foo(), then you should
> have to tell the compiler what you mean by that and what you’re doing with
> it.
>

Where a type is located in relation to a protocol is a poor proxy for
whether one was written _before_ the other. And while the writer's most
likely intent might differ depending on the order in which two things are
written, how one declares members on a type should not be determined by a
set of arbitrary rules for the compiler to guess whether the type or
protocol was written first. This kind of functionality, if you want it,
might be appropriate for a linter. It could probably even look at last
modified dates, or with a git repo, go line by line to see when each piece
of the code was written.


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


More information about the swift-evolution mailing list