[swift-evolution] Proposal: Require explicit modifier for statically dispatched extension methods (was: Universal dynamic dispatch for method calls)

Paul Cantrell cantrell at pobox.com
Wed Dec 9 23:11:20 CST 2015


> There are three reasons I like `final`:
> 
> 1) It echoes the meaning of `final` in a class—“this is the implementation and you cannot provide any other”.
> 
> 2) Swift’s general slant is towards using virtual dispatch unless it’s forbidden. (Leaving aside cases where the optimizer can prove at compile time what a dynamic dispatch would do.) That’s why we have a `final` keyword instead of a `virtual` keyword. Because of this, it’s not surprising to Swift users that you *can* override some extension methods; rather, the surprise is that you *can’t* override others. (And the *real* surprise is that you can kind-of-but-not-really override them, and Swift doesn’t complain.) I want developers to mark the surprise.
> 
> 3) Since, as I said, Swift’s slant is towards virtual dispatch, I think that if Swift eventually permits overriding of protocol extension methods, the overridable behavior should be the default, and the current static behavior should be something you request.


Well said, Brent. I agree completely with all these points.

#2 is precisely the reason I threw out that strawman proposal to open the discussion. That strawman long since torn down to satisfaction, I’ve updated the subject line.

The details of the solution are tricky, but I like this general approach with “final” (or whatever the right keyword is). It passes the smell test for me.

• • •

I’m not yet sold on @incoherent. What about preserving the current approach: whenever there are two semantically distinct methods with the same name, require the caller to disambiguate at the call site? For example:

    //––– Module Foo ———

    extension String {
        final func flip() {
            // reverse order of letters
        }
    }

    //––– Module Bar ———

    extension String {
        final func flip() {
            // turn letters upside down using funny Unicode chars
        }
    }

    //——— Third module ———

    import Foo
    import Bar

    // Please ignore the ugly syntax, and just imagine something
    // prettier with these semantics:

    "Swift".Foo::flip() // → "tfiwS"
    "Swift".Bar::flip() // → "ʇɟıʍs"
    "Swift".flip()     // compiler error: Ambiguous method "flip()"

    // Another imperfect alternative syntax (same semantic intent, though):

    ("Swift" as Foo.String).flip() // → "tfiwS"
    ("Swift" as Bar.String).flip() // → "ʇɟıʍs"
    "Swift".flip()                 // compiler error: Ambiguous method "flip()"

Both syntaxes are ugly, but set syntax aside for a moment. I’m asking about that general approach.

This disambiguation requirement would only apply if there is a pair of methods such that:

1. both methods are visible at the call site, and
2. neither one is an ancestor of the other in the same virtually dispatched override hierarchy.

Cheers,

Paul


> On Dec 9, 2015, at 6:09 PM, Brent Royal-Gordon via swift-evolution <swift-evolution at swift.org> wrote:
> 
>> Any thoughts on instead having to mark the default method implementations as `default`?
> 
> There are three reasons I like `final`:
> 
> 1) It echoes the meaning of `final` in a class—“this is the implementation and you cannot provide any other”.
> 
> 2) Swift’s general slant is towards using virtual dispatch unless it’s forbidden. (Leaving aside cases where the optimizer can prove at compile time what a dynamic dispatch would do.) That’s why we have a `final` keyword instead of a `virtual` keyword. Because of this, it’s not surprising to Swift users that you *can* override some extension methods; rather, the surprise is that you *can’t* override others. (And the *real* surprise is that you can kind-of-but-not-really override them, and Swift doesn’t complain.) I want developers to mark the surprise.
> 
> 3) Since, as I said, Swift’s slant is towards virtual dispatch, I think that if Swift eventually permits overriding of protocol extension methods, the overridable behavior should be the default, and the current static behavior should be something you request.
> 
> But this is not a terribly strong preference; `default` would be alright too. The more important point to me is that the user should acknowledge the weird behavior of shadowing a protocol extension method. In other words, I think the `@incoherent` annotation on the conformance is actually more important than the `final` or `default` keyword on the declaration.
> 
>> It still seems strange to me to consider a protocol extension that uses the `final` keyword, because a) protocols have nothing to do with classes and `final` means no subclassing
> 
> The way I see it, `final` in a class is a way of saying “All instances of this class (including subclasses) must use this implementation and cannot substitute a different one”. Similarly, `final` in a protocol means “All instances conforming to this protocol must use this implementation and cannot substitute a different one”.
> 
> That’s why @incoherent is important. It’s basically saying “I know there are final members in this type and I can’t really override them, but I want to shadow them anyway, even though the result is going to be kind of half-assed.” You could even imagine it being applied to superclasses, allowing you to shadow their `final` members in the same way you can shadow protocol extension methods.
> 
>> and b) methods defined in protocol extensions by definition can't be overridden already, so the `final` keyword is just sort of like saying "no really, I mean it, you can't do the thing you already can't do!”.
> 
> That is *exactly* the point of what I’m proposing. Just like the `override` keyword sort of says “no really, I mean it, I want to do the thing I’m doing!"
> 
> -- 
> Brent Royal-Gordon
> Architechies
> 
> _______________________________________________
> 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/20151209/2cc0d6a5/attachment.html>


More information about the swift-evolution mailing list