[swift-evolution] [Pitch] Requiring special keyword to mark protocol implementation methods

Vladimir.S svabox at gmail.com
Thu May 19 11:17:11 CDT 2016


Leonardo,
Based on the discussion for similar subject, I feel like community and core 
team does not support the idea of more verbose decoration of protocol 
implementation in type.
So, my initial proposal is trying to add the minimum of changes to the 
current state to increase the level of clarity and self-documentation of 
code, this will help the compiler to help us, plus my proposal can prevent 
some kind of problems.

As for my initial proposal. Probably the better idea to 'fix' the warning 
regarding the same name in type and in protocol extension(when there is no 
such method in protocol itself) will be not
extension S : A { reimplement d(); }
but some kind of
@warn_reimplement(S.d)


You are introducing more verbose decoration, and personally I probably 
support it, but don't feel like the discussion of it will produce any 
positive result. So I try to discuss at least this : small decoration of 
methods that were declared specifically to fulfill the protocol requirements.

On 18.05.2016 23:10, Leonardo Pessoa wrote:
> Hi Vladmir!
>
> There is something very similar to this in C#. I like this but I'd
> like to enhance it a little bit. I don't think it's necessary to
> decorate protocol methods any further but some warnings by the
> compiler would be welcome, like when pushing a type to adopt a
> protocol through an extension when the type already implements a
> protocol method (we should need an annotation to tell the compiler we
> understand this). This would be my version of the proposal:
>
>     protocol IX {
>        func somethingA()
>        func somethingB()
>     }
>
>     class X {
>        func somethingA() { ... }
>     }
>
>     @warn_implemented(IX.somethingA)  // any better ideas?
>     extension X : IX {
>        func something() implements IX.somethingB { ... }
>     }
>
> My issue here is: what if I need to adopt two protocols (from
> different vendors, I suppose) which require the same method and
> signature but for each interface you're expected to have a different
> outcome? I think better than just saying a method is an implementation
> required by a protocol is to say explicitly which protocol required
> that implementation. I'd also suggest a syntax for declaring a method
> that is not visible but through a cast to the protocol if that makes
> any sense to you.
>
> A method implementation can have a different name if you remember two
> different protocols could use the same name and signature; a new name
> would disambiguate them to us, the implements part would disambiguate
> for the compiler.
>
> What do you think?
>
> On 18 May 2016 at 04:28, Vladimir.S via swift-evolution
> <swift-evolution at swift.org> wrote:
>> I'd like to discuss declaration of protocol implementation in types.
>>
>> Ideas of this pitch is partially based on Erica Sadun's thread:
>> [Pitch] Requiring proactive overrides for default protocol implementations.
>> http://thread.gmane.org/gmane.comp.lang.swift.evolution/15496
>> And on this draft of proposal:
>> https://gist.github.com/erica/fc66e6f6335750d737e5512797e8284a
>>
>> I had read "Winding down the Swift 3 release" message, but feel like this
>> proposal makes "improvements to the consistency and feel of the language"
>> and supports the "goal of making Swift 4 as source compatible with Swift 3
>> as we can reasonably accomplish". Or this can be discussed as 'after Swift
>> 3.0' feature.
>>
>>
>> The main idea of my proposal
>>
>> Swift should help us to be explicit about what methods were defined in type
>> specifically to fulfill a protocol requirements. And so we will have more
>> understandable and self-documented code that is explicit regarding the fact
>> of protocol implementation(for reader of our code and for compiler).
>>
>> Additionally this can help to reduce potential
>> problems/error/misunderstanding in case some protocol requirement(method)
>> were *removed* - in this case (currently) our type will still have a method
>> as implementation but no such requirement in conformed protocol yet.
>>
>>
>> Details
>>
>> I propose to introduce *implement* keyword to 'mark' the methods(in type)
>> that were defined in order to conform to protocol.
>> Also, *reimplement* keyword is proposed to reflect the fact that method is
>> declared in *both* : in the type and in protocol extension (only in
>> extension, no definition of the method in protocol itself)
>>
>>
>> Rules
>>
>> * Each method in type defined to fulfill the protocol conformance should be
>> marked with `implement` keyword:
>> implement func protocolRequirement() {..}
>>
>> * Compiler produces *warning* if the same function is declared in type and
>> in protocol extension in case class conformed to that protocol. To 'fix' the
>> warning, `reimplement` should be used.
>> reimplement func f() {..} // we aware that the same method in protocol
>> extension
>>
>> * don't need to mark methods for type if conformance to protocol defined by
>> separate type extension
>>
>> * `reimplement` can be placed in defining type or as special declaration in
>> type extension anywhere in source code:
>> extension Type {
>>   reimplement methodDeclaredInBothTypeAndInProtocolExtension(..); // no body
>> here. probably `;` is required - to be discussed
>> }
>> (I don't really like this requirement, but right now don't know if we can do
>> the same by using any other method )
>>
>>
>> Current behavior of protocol extension
>>
>> When method is declared in protocol extension(*only. no in protocol itself*)
>> and in type that is conformed to the protocol, there is a possibility for
>> confusion about which method will be called. Example:
>>
>> protocol A { func a() }
>> extension A { func b() {print("Hello from b() in extension A")} }
>>
>> class B : A {
>>     func a() {}
>>     func b() {print("Hello from b() in B")}
>> }
>>
>> let instance1 = B()
>> instance1.b() // Hello from b() in B
>>
>> let instance2 : A = B()
>> instance2.b() // Hello from b() in extension A
>>
>> func f<T:A>(t: T) { t.b() }
>> f(instance1) // Hello from b() in extension A
>>
>> In this proposal I suggest compiler will generate a *warning* in this
>> case(not error). This warning can be fixed with `reimplement` keyword for
>> b() in class B.
>>
>>
>> `Override` keyword alternative
>>
>> I think that `override` keyword can not be used instead of new `implement`,
>> as the first clearly means now that method overrides one of the methods from
>> base class. Such method already has implementation in base class(in compare
>> with protocol requirement) and 'belongs' to `class` not to `protocol`. So,
>> in case of `override` keyword for protocol implementation we'll have
>> questions if super.method() should be called inside.
>> Also, usually declaration of `override` method is not required, in opposite
>> to implementation of protocol requirement.
>>
>>
>> Questions to discuss
>>
>> * Should `reimplement` be used only when exactly the same method
>> declared(arguments+return type the same) or even if just method name is the
>> same(in extension there is f(v: Float) in type f(v:Double)) ? I'd prefer the
>> second, but I don't feel this will be supported by community.
>>
>>
>> Code Examples:
>>
>> A) ------------------------------------------------
>>
>> 1. We have some protocol:
>>
>> protocol A {
>>     func a()
>>     func b()
>>     func c()
>> }
>>
>> 2. Then extension is defined for it:
>>
>> extension A {
>>     implement func a() {} // Correct, `a` was declared in `A`
>>
>>     //func b() {}
>>     // Incorrect: `b` was declared in `A`, `implement` is required
>>     // Compiler says: add `implement` keyword or remove implementation
>>
>>     func d() {} // Correct, new method in extension
>>
>>     //implement func e() {}
>>     // Incorrect: `e` was not declared in `A`, `implement` should be removed
>>     // Compiler says: remove `implement` keyword or remove implementation
>> }
>>
>> 3. *We* are writting the type S that conforms to A protocol:
>>
>> struct S: A {
>>     implement func a() {} // Correct. We implemented A's requirement
>>
>>     //func b() {}
>>     // Incorrect: add `implement` keyword or rename the method
>>
>>     implement func b() {} // Correct
>>     implement func c() {} // Correct
>>
>>     //implement func f() {}
>>     // Incorrect: No `f` declaration in protocol. Compiler: rename method or
>> drop `implement` keyword
>>
>>     //func d() {}
>>     // Incorrect: Possible accidental name match.
>>     // Compiler: rename method or add `reimplement` keyword
>>
>>     reimplement func d() {} // Correct. We are explicit about the fact that
>> our type has the same function as in extension of conformed protocol
>> }
>>
>>
>> B) ------------------------------------------------
>>
>> 1. Having declared protocol:
>>
>> protocol A {
>>     func a()
>>     func b()
>>     func c()
>> }
>>
>> 2. Have defined extension
>>
>> extension A {
>>     implement func a() {} // Correct, `a` was declared in `A`
>>
>>     //func b() {}
>>     // Incorrect: `b` was declared in `A`, `implement` is required
>>     // Compiler says: add `implement` keyword or remove implementation
>>
>>     func d() {} // Correct, new method in extension
>>
>>     //implement func e() {}
>>     // Incorrect: `e` was not declared in `A`, `implement` should be removed
>>     // Compiler says: remove `implement` keyword or remove implementation
>> }
>>
>> 3. Have a type that we can't/don't want to change
>>
>> struct S { // at this moment S don't care about any protocol
>>     func a() {}
>>     func b() {}
>>     func c() {}
>>     func d() {}
>> }
>>
>> 4. *We* need (for some task) to conform the S type to protocol A in our own
>> code. So we do:
>>
>> extension S : A {
>>     // no need of any special steps for a(), b(), c()
>>     // as we just said "we sure S conforms to A"
>>
>>     // but we need to care about special case - d() method, which is defined
>> in S type and in extension of A protocol
>>     reimplement d();  // probably `;` is required here
>> }
>>
>>
>> C) ------------------------------------------------
>>
>> 1. Have protocol
>>
>> protocol A {
>>     func a()
>>     func b()
>>     func c()
>> }
>>
>> 2. Have a Type
>>
>> struct S { // at this moment S don't care about any protocol
>>     func a() {}
>>     func b() {}
>>     func c() {}
>>     func d() {}
>> }
>>
>> 3. Conforms to protocol
>>
>> extension S : A {
>>     // no need of any special steps for a(), b(), c()
>>     // as we just said "we sure S conforms to A"
>>     // here(at the moment of *writing*) S don't know about any extension of
>> A
>> }
>>
>> 4. Now protocol extension is defined:
>>
>> extension A {
>>     implement func a() {} // Correct, `a` was declared in `A`
>>
>>     //func b() {}
>>     // Incorrect: `b` was declared in `A`, `implement` is required
>>     // Compiler says: add `implement` keyword or remove implementation
>>
>>     func d() {} // Correct, new method in extension
>> }
>>
>> 5. But now we have a problem : same d() method in S and in A extension
>> Compiler will raise a warning : Possible accidental name match of d() in S,
>> also defined in extension of A. Change method name or add `reimplement`
>> keyword
>>
>> In case we can't or don't want to change the method name(in type or in
>> protocol) - the only solution is to say "it's OK" to the compiler anywhere
>> in our code:
>>
>> extension S {
>>     reimplement d();  // notify the compiler that we are aware of the same
>> names
>> }
>>
>> Thank you for your opinions on this.
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution at swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>


More information about the swift-evolution mailing list