[swift-evolution] Mark protocol methods with their protocol

Adrian Zubarev adrian.zubarev at devandartist.com
Fri Sep 16 15:24:05 CDT 2016


I don’t really like the idea of override(ProtocolName), but I’d support the single override here. On value types it’s easier to recognize the member of a protocol which had a default implementation.

I don’t feel like adding override to all members that replaces some default implementation will break anything. Furthermore, I’d love to see the addition where we could call the default implementation.

Here is some bikeshedding:

protocol A {}

extension A {
   func foo() { .. }
}

protocol B : A {}

extension B {
   // overriding default implementation from an other one!?  
   override func foo() {
        // call default implementation of A
       default.foo()
    }   
}

struct C : A {
   // overriding some default implementation  
   override func foo() {
      // call default implementation
       default.foo()
    }
}

struct D : B {
      // overriding some default implementation  
   override func foo() {
      // call default implementation B
      // which will also call default implementation of A
       default.foo()
    }
}


-- 
Adrian Zubarev
Sent with Airmail

Am 16. September 2016 um 20:45:05, Vladimir.S via swift-evolution (swift-evolution at swift.org) schrieb:

David, thank you for a real-word example when such feature will be very  
useful and can protect from hard-to-find bugs. IMO This shows that we  
should find a solution for the problem as soon as possible.

Such or similar question was discussed already in an number of threads, for  
example in "Requiring proactive overrides for default protocol  
implementations." and in "Requiring special keyword to mark protocol  
implementation methods", probably in other threads also.

The first is that `override` is not used in structs, so IMO it will be  
alien here.
Second, if protocol has no default implementation for the method- would you  
require the `override(Protocol)` also?

Then, in case you will not require a keyword when no default implementation  
- you should think about retrospective adding of extension.

I.e. imagine, you have a source file, let's call it SomeClass.swift which  
you can't or don't want to change(this could be some complex source from  
3rd party, from github, or from other developer of your company). This file  
compiles without problems. It contains:

public protocol Foo { func foo() }
public class Some: Foo { func foo() {...} }

You added SomeClass.swift to your project and in your My.swift you added  
default implementation for Foo protocol:

extension Foo { func foo() {...} }

So, now, when you compile your project, there is default implementation for  
foo() and class Some should contains `override(Foo)`, but you can't change  
SomeClass.swift.


The only solution I see here, is if this `override(Foo)` will be optional,  
and just express developer's intention, if he/she wants this. I.e. it is  
not required, but if you specify it - compiler will check this intention.
But AFAIR unfortunately someone from core team mentioned that they don't  
want such optional solution.

And, at the end, I do think the real reason of your problem is not that  
protocol method has default implementation, but that  
`viewController(with:properties:)` definition in `FooController` does not  
say for compiler(and compiler does not check this) that this method was  
defined *exactly* to confirm to protocol. I.e. you can't clearly express  
your intention regarding why this method is here. Check this example:

Let's assume you defined protocol Foo in FooProto.swift file:

public protocol Foo { func foo() }

and have class `Some` conformed to Foo in SomeClass.swift:

public class Some : Foo { func foo() {...} }

it is clear *why* foo is here..

OK, now, let's assume you changed Foo protocol in the way, that  
SomeClass.swift *still* compiles :

public protocol Foo { func bar() }
extension Foo {
func bar() {...}
}

Now, SomeClass.swift still compiles but it contains *wrong* intention that  
foo() method is an implementation of protocol requirement. And this can  
lead to bugs/unexpected behavior.


I think what we do need a way to clearly shows intention that we defined  
some method *exactly* because the conformed protocol has it and to make  
compiler check this.

My favorite solution is 'implements' keyword inside class/struct to  
highlight that I defined this method as implementation for the protocol  
requirement. IMO solves a big percent of discussed issues with just one  
added keyword, that also will help with understanding the code when you  
read it.

Other solution that was mentioned by (as I remember) member of core team is  
treat class extension with protocol conformance as such intention, i.e.  
when you say
extension Some: Foo {..}
compiler will understand this as all methods inside such extension must  
'belongs' to the Foo protocol, i.e. if there is some method that does not  
exist in Foo - it will raise an error. But in this case we need to require  
that each protocol conformance will be declared as extension, not inline in  
class definition. Personally I don't believe in this solution.


On 16.09.2016 18:29, David Beck via swift-evolution wrote:
> With the transition from Swift 2 -> 3 IБ─≥ve started running into one
> particular issue VERY often (although itБ─≥s not necessarily specific to the
> transition). If a protocol method is optional (either because it is an
> @objc optional or because it has a default implementation) there is a risk
> that the conformer will have a misspelled or slightly incorrectly typed
> implementation of the method. For instance:
>
> protocolRouteDestinationViewController: class{
> staticfuncviewController(with url: URL, properties: [String:String]) ->
> UIViewController?
> }
>
> extensionRouteDestinationViewControllerwhereSelf: UIViewController {
> staticfuncviewController(with url: URL, properties: [String:String]) ->
> UIViewController? {
> returnSelf.init()
> }
> }
>
> classFooController: UIViewController, RouteDestinationViewController{
> staticfuncviewController(with url: URL, properties: [String:Any]) ->
> UIViewController? {
> returnFooController(properties: properties)
> }
> }
>
> Notice the issue there? Properties is supposed to be [String:String], but
> FooController uses [String:Any] (this is an exact issue I ran into after a
> small refactor). When viewController(with:properties:) is called, it will
> use the default implementation instead of what the compiler sees as a
> completely different method. Over the betas the compiler has gotten better
> warnings about this, but is still not 100%.
>
> Other cases of this issue are common with imported ObjC protocols that have
> different naming in Swift. In some cases an @objc name must be applied to
> ensure it is declared in a way that the protocol can see it.
>
> We solve this problem with subclassing by requiring Б─°overrideБ─². If the
> override keyword is present but the superclass doesnБ─≥t have a matching
> method, the compiler warns us about it. Similarly if the superclass
> implements the same method and the subclass doesnБ─≥t include override, we
> get a warning so that it is clear that you are overriding behavior.
>
> For protocols, I donБ─≥t think a required keyword would be the best approach.
> ItБ─≥s a completely valid case that a type could conform to a protocol using
> existing methods, perhaps even from a different module. Further, a single
> method could satisfy multiple protocols, and be overriden from a
> superclass. What I would propose would be something like an optional
> override(<#protocol name#>). Something like the following:
>
> override(RouteDestinationViewController) staticfuncviewController(with url:
> URL, properties: [String:Any]) -> UIViewController? {
> returnFooController(properties: properties)
> }
>
> A method should be able to include multiple overrides (including a bare
> override to indicate that it is overriding a class method).
>
> Thoughts? Are you seeing similar issues?
>
> *David Beck*
> http://davidbeck.co
> http://twitter.com/davbeck
> http://facebook.com/davbeck
>
>
>
> _______________________________________________
> 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
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160916/d0db309c/attachment.html>


More information about the swift-evolution mailing list