[swift-evolution] Mark protocol methods with their protocol

Vladimir.S svabox at gmail.com
Fri Sep 16 13:44:24 CDT 2016


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
>


More information about the swift-evolution mailing list