[swift-evolution] Mark protocol methods with their protocol

Xiaodi Wu xiaodi.wu at gmail.com
Fri Sep 16 16:08:45 CDT 2016


We've had this discussion on the list multiple times already. The gist of
the difficulty here is that most proposals for a mandatory keyword don't
permit retroactive modeling, so it's a no-go. On the other hand, the core
team seems to take a dim view to optional syntax, since that's more in the
ballpark of linters.

I really don't see anything new here that we haven't already discussed at
length...


On Fri, Sep 16, 2016 at 15:25 Adrian Zubarev via swift-evolution <
swift-evolution at swift.org> wrote:

> 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
>
> _______________________________________________
> 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/f6acc590/attachment.html>


More information about the swift-evolution mailing list