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@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to