[swift-evolution] Mark protocol methods with their protocol

Xiaodi Wu xiaodi.wu at gmail.com
Tue Sep 20 16:46:35 CDT 2016


I'm not sure I understand. What compiler or language support is missing for
StringCore?
On Tue, Sep 20, 2016 at 16:42 Karl via swift-evolution <
swift-evolution at swift.org> wrote:

> On 20 Sep 2016, at 23:28, Karl <raziel.im+swift-evo at gmail.com> wrote:
>
>
> On 20 Sep 2016, at 18:43, Nevin Brackett-Rozinsky via swift-evolution <
> swift-evolution at swift.org> wrote:
>
> I have been following this discussion (as well as similar threads earlier
> this year) and listening to the ideas put forth by all sides.
>
> It seems to me that the fundamental difference between classes and
> protocols is that classes inherit implementation whereas protocol
> conformance is a promise about interface.
>
> When a class or struct or enum declares itself as conforming to a
> protocol, that means it has all the members specified in the protocol. The
> protocol conformance simply codifies a fact about the type itself: namely
> that all those members are present.
>
> In this model, any keyword such as `implements` on each conforming member
> would introduce substantial boilerplate for negligible gain. The purpose of
> a protocol is to communicate that certain members are available, not to
> make declaring those members more onerous.
>
> However, default implementations for protocols blur the line. Now there is
> actual implementation being inherited. A conforming type may choose to roll
> its own version of a method, or to utilize the default provided by the
> protocol. This is closer to the situation with subclassing.
>
> Moreover, a protocol which conforms to another protocol may itself define
> (or redefine!) default implementations for members of that other protocol.
> This can create “inheritance chains” of protocol default implementations. I
> think there is value in being able to refer to (and call) the inherited
> default implementation through some sort of `super` functionality.
>
> On the other hand, the existence of a default implementation in a protocol
> is in large part merely a convenience: a courtesy so that each conforming
> type need not rewrite the same boilerplate code.
>
> A type which conforms to a protocol may accept the default or it may
> provide its own implementation, but it is not “overriding” anything. The
> default implementation was offered as a convenience, to be taken or left as
> needed. Thus I do not think any keyword (neither `override` nor
> `implements`) should be required in that case either.
>
> The frequently-raised point regarding near-miss member names deserves some
> attention. Several people have expressed a desire for the compiler to
> assist them in determining whether a given member does or does not meet a
> protocol requirement. Specifically, when a type conforms to a protocol with
> a default implementation, and the type defines a member with a similar
> signature, it is not obvious at glance if that member matches the protocol.
>
> I think this is a job for linters and IDEs. For example, syntax
> highlighting could distinguish members which satisfy a protocol
> requirement, thereby providing immediate visual confirmation of success.
>
> Having followed the lengthy discussion and weighed the numerous ideas put
> forth, I come down firmly on the side of no keyword for protocol
> conformance.
>
> A protocol describes an interface and provides a set of customization
> points. It may also, as a convenience, offer default implementations. The
> protocol simply describes the capabilities of its conforming types, and any
> default implementations are there to make things easier for them.
>
> Conforming types should not be afflicted with extraneous keywords: that
> would run contrary to the purpose of having protocols in the first place.
>
> Nevin
>
>
> On Tue, Sep 20, 2016 at 11:16 AM, Xiaodi Wu via swift-evolution <
> swift-evolution at swift.org> wrote:
>
>> As I mentioned above, I agree that better diagnostics for near-misses are
>> necessary, but they are possible without new syntax. There is no win in
>> avoiding unintentional behavior because, without a default implementation,
>> these issues are caught at compile time already.
>>
>> On Tue, Sep 20, 2016 at 10:14 Vladimir.S via swift-evolution <
>> swift-evolution at swift.org> wrote:
>>
>>>
>>>  > extension P {
>>>  > implement func foo() -> [String : String] { return [:] }
>>>  > }
>>>
>>> Yes, it seems like we need `implement` (or `override` as another
>>> suggestion) in protocol extension also just for the same reasons - be
>>> clear
>>> about our intention regarding implementing the requirement, to show that
>>> this func *depends* on the previous definition of P protocol and to avoid
>>> possible mistakes related to protocol conformance.
>>>
>>> On 20.09.2016 17:38, Charles Srstka wrote:
>>> >> On Sep 20, 2016, at 8:17 AM, Vladimir.S via swift-evolution
>>> >> <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>>> >>
>>> >> On 20.09.2016 3:03, Xiaodi Wu via swift-evolution wrote:
>>> >>> I definitely think Vladimir's suggestion is a great starting point,
>>> IMO.
>>> >>>
>>> >>> However, I think it could be improved in one key respect where
>>> previous
>>> >>> proposals using `override` are superior. Namely, the proposed
>>> `implement`
>>> >>> keyword adds no additional safety when a type implements a protocol
>>> >>> requirement that doesn't have a default implementation. This is
>>> because, if
>>> >>
>>> >> Yes, *at the moment of writing* the type's code there could be no
>>> default
>>> >> implementation for protocol requirement. But, *at the moment of
>>> >> compilation* such default implementation could appear.
>>> >>
>>> >> Let's discuss such scenario in case we'll take your suggestion:
>>> >>
>>> >> You got SomeClass.swift file, 3rd party file you don't want to change
>>> or
>>> >> changes are not allowed. Content:
>>> >>
>>> >> public protocol SomeProtocol {
>>> >> func foo()
>>> >> }
>>> >>
>>> >> public class SomeClass : SomeProtocol {
>>> >> func foo() {...} // no default implementation *at the moment of
>>> writing*,
>>> >> no need in `overload`
>>> >> }
>>> >>
>>> >> Now, you adds SomeClass.swift file to your project and in some *other*
>>> >> file you write:
>>> >>
>>> >> extension SomeProtocol {
>>> >> func foo() {...}
>>> >> }
>>> >>
>>> >> As you see, you don't control the SomeClass.swift but you suggest in
>>> this
>>> >> case SomeClass.foo() should be defined with `override`.
>>> >>
>>> >> With 'implement' SomeClass.foo() will be marked initially and will
>>> save
>>> >> us if protocol's requirement PLUS default implementation changed.
>>> >
>>> > Requiring the ‘implement’ keyword can help us even if no default
>>> > implementation is involved. Consider:
>>> >
>>> > protocol P {
>>> > func foo() -> [String : Any]
>>> > }
>>> >
>>> > struct S : P {
>>> > func foo() -> [String : String] { return [:] }
>>> > }
>>> >
>>> > We will get an error here that S does not conform to P. However, this
>>> is
>>> > not the correct error, since S in fact *tries* to conform to P, but it
>>> has
>>> > a mistake in a method signature. This misleads us as to the true
>>> nature of
>>> > the problem, and if S has enough members in it that we fail to spot the
>>> > existing foo(), we might solve the problem by reimplementing foo(), and
>>> > leaving the original foo() as dangling dead code. Having an ‘implement’
>>> > keyword on the existing foo() function would change the compiler error
>>> to
>>> > let us know that we have an existing foo() that is incorrectly
>>> declared.
>>> >
>>> > In addition, ‘implement’ can help us when the declaration in question
>>> *is*
>>> > the default implementation:
>>> >
>>> > protocol P {
>>> > func foo() -> [String : Any]
>>> > }
>>> >
>>> > extension P {
>>> > implement func foo() -> [String : String] { return [:] }
>>> > }
>>> >
>>> > Here we will get an error with the proposed ‘implement’ keyword,
>>> because
>>> > foo() does not have a signature matching anything in the protocol,
>>> whereas
>>> > without ‘implement’ we would happily and silently generate a useless
>>> > dangling function that would never be used, and then pass the buck to
>>> the
>>> > concrete type that implements P:
>>> >
>>> > protocol P {
>>> > func foo() -> [String : Any]
>>> > }
>>> >
>>> > extension P {
>>> > func foo() -> [String : String] { return [:] } // The error is here:
>>> > }
>>> >
>>> > struct S : P {} // But it gets reported here.
>>> >
>>> > Charles
>>> >
>>> _______________________________________________
>>> swift-evolution mailing list
>>> swift-evolution at swift.org
>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>
>>
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution at swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>
>>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
>
> I agree that a new keyword is unwanted. Conforming to protocols is quite a
> common thing, so you want it to be easy to remember.
>
> I think the best way is to prefix the member name with the protocol, e.g:
>
> protocol MyProto {
>     var aVariable : Int
>     func aFunction()
> }
> class MyClass : MyProto {
>     var MyProto.aVariable : Int
>     func MyProto.aFunction() { … }
> }
>
> This is consistent with how we refer to other members of types (e.g.
> “extension MyClass.MyInternalClass”). It will be easy for autocompletion to
> provide good suggestions, too.
> As I see it, the only problem is what if `MyClass` wants its own function
> called `aFunction()`? What if the same name satisfies 2 protocols, which do
> you write?
>
> The way to solve all of the problems in a consistent way is to make the
> function actually called “MyProto.aFunction”, and for it to be a separate
> function from plain “aFunction()” or from “SomeotherProto.aFunction”.
>
> I believe it is crucial to protocols that we can do this. Maybe I have
> some complex data structure and it has its own API, but I want people to be
> able to view it as a Collection. By conforming to Collection, I reserve
> lots of keywords and indexing operations which I now can’t use in my own
> API. Maybe I’m just providing Collection as a convenience to work with
> generic algorithms, but my own API has more efficient semantics for some
> operations. We’re relegated to using less-obvious and legible names in
> order to avoid conflicts.
>
> We have a way to work around this, which String uses - create a struct
> which references your object and calls internal methods such as
> “_collection_count” so you can have separate interfaces. This adds up to
> quite a lot of boilerplate and maintenance overhead.
>
>
> Also to add here: you’re basically implementing what I’m proposing
> manually if you do this; only you don’t get language/compiler support.
> String basically does this - it shares StringCore with UTF8View and
> defines some internal functions to support it.
>
> The String views could then be made in to protocols on String, turning
> “UTF8View” in to “UTF8Representable”, and opening up algorithms which can
> work on generic sequences of UTF8 bytes. I think that’s pretty cool, and
> could open up better integration with other types which are (for example)
> UTF8Representable — for example a stream of UTF8 bytes (depending on how
> flexible implementation allows us to make the protocol).
>
>
> I don’t agree that Protocol conformances are kind-of incidental, as others
> here have written. This isn’t like Objective-C where anything that has the
> correctly-named methods conforms. Protocol conformances are completely
> explicit, and in fact we have empty protocols (“marker protocols”) for
> exactly that purpose. I think it is consistent that we make every member of
> a conformance specify which protocol it belongs to, and to have its name
> scoped to that protocol.
>
> Karl
>
>
> CC-ing Dave A, to understand better if this fits with the vision of
> protocols
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160920/d9c57ea6/attachment.html>


More information about the swift-evolution mailing list