[swift-evolution] Keyword for protocol conformance

Xiaodi Wu xiaodi.wu at gmail.com
Fri Aug 26 16:27:37 CDT 2016


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

> On Aug 26, 2016, at 3:58 PM, Xiaodi Wu <xiaodi.wu at gmail.com> wrote:
>
>
> On Fri, Aug 26, 2016 at 3:43 PM, Charles Srstka <cocoadev at charlessoft.com>
>  wrote:
>
>>
>> On Aug 26, 2016, at 3:19 PM, Xiaodi Wu <xiaodi.wu at gmail.com> wrote:
>>
>> 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.
>>
>>
>> Why should it matter when the programmer wrote it?
>>
>
> I don't know--that's your suggestion, not mine: "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..."
>
>
>> One is the declaration, the other is an add-on to it. Conceptually, the
>> type is constructed first, and then things are bolted on (and in
>> Objective-C, that’s literally what happened; I don’t know how it is
>> implemented in Swift, but conceptually this is how the mental model works).
>>
>> Should I not have to add an “override” keyword to a subclass method
>> simply because I wrote that method first and only refactored it into a
>> superclass method after the fact?
>>
>> This seems like a fairly silly objection, IMO.
>>
>> I agree, it seems silly. Can you explain what you meant?
>
>
> Think of it—even if you wrote the whole thing—as if each file were written
> by a different person. The programmer who wrote File A defines the type.
> The programmer who wrote File B added conformance to a protocol to the
> type. Conceptually, one comes before the other, since the type has to be
> made before it can be extended, yes?
>

And you argue that if both parts were in the same file, then conceptually
the type no longer "comes before" its protocol conformance? That seems like
an arbitrary distinction to me.
Surely, if I subscribed to your notion that types "come before" their
conformance to a protocol, then it doesn't matter if they're separated in
different files or not: no keyword should be necessary for a declaration to
override a default protocol implementation, because the type conceptually
"comes before" that default implementation.


> And I don’t know about you, but when I add methods to a type whose purpose
> are to satisfy a protocol, I put them near the declaration of conformance,
> not somewhere on the other side of the universe. If I’m retroactively
> adding conformance to something in a different translation unit, then the
> methods involved originally served some other purpose independent of the
> protocol. Otherwise, it’s just terrible design, IMO.
>
> On Aug 26, 2016, at 3:23 PM, Xiaodi Wu <xiaodi.wu at gmail.com> wrote:
>>
>> If you want it all to compile at the same time, well, we’ve still got
>>> access to all the Objective-C runtime functions in Swift. One can also
>>> write the assembly by hand. Things like “override” aren’t security
>>> features; they’re there to help you do the right thing. If you’re
>>> deliberately trying to do the wrong thing, I don’t think that can strictly
>>> be prevented.
>>>
>>
>> The current syntax is not the "wrong thing"--and a future language
>> feature shouldn't leave a loophole where someone can choose either one or
>> another totally different set of rules for conforming a type to a protocol;
>> there should be one syntax for doing that in Swift.
>>
>>
>> The current syntax allows many opportunities to do the wrong thing.
>>
>> This is the wrong thing:
>>
>> protocol P {
>> func foo(bar: Baz)
>> }
>>
>> extension P {
>> func foo(bar: Baz) {}
>> }
>>
>> struct S: P {
>> func foo(baz: Baz) {}
>> }
>>
>> Refactoring this can result in another wrong thing:
>>
>> protocol P {
>> func foo(bar: Baz, qux: Quux)
>> }
>>
>> extension P {
>> func foo(bar: Baz) {}
>> }
>>
>> etc. etc. etc.
>>
>> Currently it’s hard for a linter to catch things like this, because
>> there’s no way to know that I *didn’t* mean to define a similarly, but not
>> exactly, named function, just as there’s no way to know that I *didn’t*
>> mean to provide a simplified version of the function in the extension. And
>> etc. If I could tell the compiler what I mean by those declarations,
>> suddenly they it becomes possible to check them for accuracy.
>>
>
> Or, instead, you could tell a linter these things if you choose; I'm
> saying your proposal of having distinct before-the-fact and after-the-fact
> syntax for protocol conformance doesn't make for a good language feature,
> IMO.
>
>
> But that was only one of a set of four options which I presented, of which
> more are assuredly possible. If you want the syntax to be exactly the same,
> we could even do that, just by declaring the methods in the extension with
> no bodies:
>
> extension S: P {
> conform func foo()
> }
>
> Honestly, I’m not married to any one syntax for retroactive conformances;
>

Then let me convince you that perhaps what you want is a linter that parses
structured comments, which can be used to say whether this or that method
is intended to override a particular default protocol implementation or
whether some conformance is a retroactive one. There's enormous flexibility
there, and none of it impacts people who have retroactive modeling needs
that don't neatly fit into this sort of "comes before" and "comes after"
model.

the typical kind are the ones I’m more concerned with, because they offer a
> great potential for mistakes as compared with the traditional inheritance
> model, and I’m finding that the increased brittleness is the biggest
> drawback I’m noticing in refactoring an old Objective-C hierarchy to the
> Swift protocol-oriented model.
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160826/313690e3/attachment.html>


More information about the swift-evolution mailing list