[swift-evolution] [Pitch] Requiring special keyword to mark protocol implementation methods
Leonardo Pessoa
me at lmpessoa.com
Wed May 18 15:10:27 CDT 2016
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