[swift-evolution] Making protocol conformance inheritance controllable

T.J. Usiyan griotspeak at gmail.com
Thu Dec 10 23:29:36 CST 2015


I think that this is a good idea overall. I agree that `required override`
might necessary as well.

---
TJ

On Fri, Dec 11, 2015 at 7:34 AM, Joe Groff via swift-evolution <
swift-evolution at swift.org> wrote:

> I've had a number of twitter conversations with users who have valiantly
> fought our type system and lost when trying to make their protocols
> interact well with non-final classes. A few from recent memory:
>
> - Rob Napier struggling to implement a `copy` method that works well with
> subclasses: https://twitter.com/cocoaphony/status/660914612850843648
> and making the observation that the interaction of protocol conformance
> and subtyping is very difficult to teach.
>
> - Matt Bischoff trying to make Cocoa class clusters retroactively conform
> to his factory protocol:
> https://twitter.com/anandabits/status/664294382774849536
>
> and Karl Adam trying to do the same:
> https://gist.github.com/thekarladam/c3094769cc8c87bf55e3
>
> These problems stem from the way protocol conformances currently interact
> with class inheritance—specifically, that if a class conforms to a
> protocol, then all of its possible derived classes also conform. This seems
> like the obvious way things should be, but in practice it ends up fighting
> how many classes are intended to be used. Often only a base class is
> intended to be the public interface, and derived classes are only
> implementation details—Cocoa class clusters are a great example of this.
> The inheritance of protocol conformances also imposes a bunch of knock-on
> complexity on conforming classes—initializer requirements must be satisfied
> by `required` initializers (which then must be overridden in all derived
> classes, to the pain of anyone touching an NSCoding-inherited class), and
> methods often must return dynamic `Self` when they'd really prefer to
> return the base class.
>
> To mitigate these issues, I'd like to float the idea that protocol
> conformances *not be* inherited by default. If you declare a class as
> conforming to a protocol, only exactly that class can be bound to a type
> parameter constrained by that protocol:
>
> protocol Runcible {}
>
> class A: Runcible { }
> class B { }
>
> func foo<T: Runcible>(x: T) {}
>
> foo(B()) // calls foo with T == A
>
> Since subclasses are still subtypes of the base class, in many cases
> client code won't have to change at all, since derived instances can
> implicitly upconvert to their conforming base class when used in protocol
> types or generics that only the base class conforms to. (There are cases
> like if the type parameter appears in a NonCovariant<T> type where this
> isn't possible, though.) Protocol requirements for a non-inherited
> conformance don't need to be `required` initializers, or maintain covariant
> returns:
>
> protocol Fungible {
>   init()
>   static func funged() -> Self
> }
>
> class C: Fungible {
>   init() {} // Non-required init is fine, since subclasses aren't directly
> Fungible
>
>   // Non-Self return is fine too
>   class func funged() -> C { return C() }
> }
>
> An individual subclass that wanted to refine the conformance could do so
> by `override`-ing it, and providing any necessary covariant overrides of
> initializers and methods:
>
> class D: C, override Fungible {
>   // D must provide its own init()
>   init() { super.init() }
>
>   // D must override funged() to return D instead of C
>   override class func funged() -> D { return D() }
> }
>
> And if a class hierarchy really wants to impose a conformance on all
> possible subclasses, as happens today, we could let you opt in to that:
>
> class E: required Fungible {
>   // init() must be required of all subclasses
>   required init() { }
>
>   // funged() must return a covariant object
>   class func funged() -> Self { return Self() }
> }
>
> This is undoubtedly a complication of the language, but I think it might
> let us more accurately model a lot of things people seem to want to do in
> practice with class hierarchies and protocols, and it simplifies the
> behavior of the arguably common case where inheritance of the conformance
> isn't desired. What do you all think?
>
> -Joe
>
> _______________________________________________
> 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/20151211/42c4dfa0/attachment.html>


More information about the swift-evolution mailing list