[swift-evolution] Proposal: Universal dynamic dispatch for method calls

Paul Cantrell cantrell at pobox.com
Tue Dec 8 23:31:04 CST 2015


Gwendal Roué wrote:
> Whatever the direction this proposal is aiming at, please remember that it is desirable for some APIs to let adopting types "override" the default implementation provided by protocols.


I would certainly hope nobody is proposing changing that! Once a method is virtually dispatched, it should be virtual all the way down to the implementing type.

P


> On Dec 8, 2015, at 10:21 PM, Gwendal Roué via swift-evolution <swift-evolution at swift.org> wrote:
> 
>> Le 9 déc. 2015 à 00:26, Kevin Ballard via swift-evolution <swift-evolution at swift.org> a écrit :
>> 
>>> Keep in mind that what I’m proposing here doesn’t actually change Swift’s runtime behavior at all. Note #2—you’re *required* to make protocol extension members `final` unless they’re listed in the protocol declaration. What I’m proposing is merely a series of compile-time statements used to tell swiftc that, yes, I know this is going to happen.
> 
> Whatever the direction this proposal is aiming at, please remember that it is desirable for some APIs to let adopting types "override" the default implementation provided by protocols.
> 
> The current static dispatch of protocol extensions allows adopting types to perform such an "override":
> 
>    protocol Feature { }
>    extension Feature {
>        func run() {
>            // default implementation
>        }
>    }
>    struct S : Feature {
>        func run() {
>            // "inherited" from Feature:
>            (self as Feature).run()
>            // extra code
>            ...
>        }
>    }
> 
> This is important, because *without* this static dispatch, the protocol P *must* be turned into a *base class* as soon as three conditions are met:
> 
> - the implementation inside the run() function is rather complex
> - it is desirable to let adopting types able to alter the default behavior.
> - bloating the API and the documentation with extra global functions or extra methods that work around this limitation of the language is not desirable
> 
>    // Terse API with a Feature base class:
>    class Feature {
>        func run() {
>            // rather complex implementation
>        }
>    }
>    class C : Feature {
>        func run() {
>            // Inherited from Feature:
>            super.ext()
>            // extra code
>            ...
>        }
>    }
> 
>    // Non-terse API with extra methods and documentation:
>    protocol Feature { }
>    extension Feature {
>        func run() {
>            self._run()
>        }
>        /// Don't call this method directly, but use run() instead.
>        /// Adopting types may call this method in their own implementation
>        /// of run().
>        func _run() {
>            // default implementation
>        }
>    }
>    struct S : Feature {
>        func run() {
>            // "inherited" from Feature:
>            self._run()
>            // extra code
>            ...
>        }
>    }
> 
> You have understood that I'm against those extra methods and documentation, and that I prefer the base class solution, despite protocols being all the rage.
> 
> Actually, the use case I'm talking here is not properly addressed by the current state of Swift because of a bug with mutating methods https://bugs.swift.org/browse/SR-142 which has the consequence of forcing APIs to keep on exposing a base class instead of a protocol (see https://github.com/groue/GRDB.swift/issues/12 for a practical problem).
> 
> Anyway, please remember that it is desirable for some APIs to let adopting types "override" the default implementation provided by protocols.
> 
> Gwendal Roué
> 
> _______________________________________________
> 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