<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class="">I still don’t understand what this proposal is actually proposing in cases like this:</div><div class=""><br class=""></div><div class="">class Root {}</div><div class="">class ImplementerOfA : Root, ProtocolA {}</div><div class="">class ImplementerOfB : ImplementerOfA, ProtocolB {}</div><div class="">class Base : ImplementerOfB {}</div><div class=""><br class=""></div><div class="">func exampleFunction<</div><div class=""> T:Base</div><div class=""> where</div><div class=""> T:ProtocolA,</div><div class=""> T:ProtocolB>(target: T) -> Whatever</div><div class=""><br class=""></div><div class="">…if I have this:</div><div class=""><br class=""></div><div class="">class CustomizedBase : Base {}</div><div class=""><br class=""></div><div class="">…what is supposed to happen if I try to write this:</div><div class=""><br class=""></div><div class="">let whatever = exampleFunction(CustomizedBase())</div><div class=""><br class=""></div><div class="">...?</div><div class=""><br class=""></div><div class="">If I understand the logic in the proposal, it seems like I *can’t* call `exampleFunction` here with `CustomizedBase`:</div><div class=""><br class=""></div><div class="">- it can’t be `CustomizedBase` b/c it doesn’t (re)implement `ProtocolA` or `ProtocolB`</div><div class="">- it can’t be `Base` b/c it doesn’t (re)implement `ProtocolA` or `ProtocolB`</div><div class=""><br class=""></div><div class="">…and even if we change it to this: </div><div class=""><br class=""></div><div class=""><div class="">func exampleFunction<</div><div class=""> T:Root</div><div class=""> where</div><div class=""> T:ProtocolA,</div><div class=""> T:ProtocolB>(target: T) -> Whatever</div><div class=""><br class=""></div><div class="">…then we still can’t call it with `CustomizedBase`, since:</div><div class=""><br class=""></div><div class=""><div class="">- it can’t be `CustomizedBase` b/c it doesn’t (re)implement `ProtocolA` or `ProtocolB`</div><div class="">- it can’t be `Base` b/c it doesn’t (re)implement `ProtocolA` or `ProtocolB`</div></div><div class=""><div class="">- it can’t be `ImplementerOfB` b/c it doesn’t (re)implement `ProtocolA` </div></div><div class="">- it can’t be `ImplementerOfA` b/c it doesn’t implement `ProtocolB` </div><div class="">- it can’t be `Root` b/c it doesn’t implement `ProtocolA` or `ProtocolB` </div><div class=""><br class=""></div><div class="">…so we can’t make this call, no?</div><div class=""><br class=""></div></div><div class="">Am I missing something obvious in either example? If so, which type would get matched (in either example)?</div><div class=""><br class=""></div><div><blockquote type="cite" class=""><div class="">On Dec 14, 2015, at 8:08 PM, Jordan Rose via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;">At first this didn't make any sense to me. Now it makes some kind of twisted sense, and I'm working my way through the details:</div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><br class=""></div><blockquote class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; margin: 0px 0px 0px 40px; border: none; padding: 0px;"><div class="">protocol Proto {<span class="Apple-converted-space"> </span><i class="">/*…*/ </i>}</div><div class="">class Base : Proto {<span class="Apple-converted-space"> </span><i class="">/*…*/</i> }</div><div class="">class Subclass : Base {}</div></blockquote><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><br class=""></div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;">- Protocols with no initializer requirements and no use of 'Self' are trivially safe here, because there's no way to recover the original type.</div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><br class=""></div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;">- Methods returning 'Self' will silently return the base type. This is often reasonable, but it's still a little weird. There's also no way to have a protocol that <i class="">requires</i> dynamic-self behavior for a factory method.</div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><br class=""></div><blockquote class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; margin: 0px 0px 0px 40px; border: none; padding: 0px;">Subclass.createViaProtocol()<i class=""><span class="Apple-converted-space"> </span>// produces a Base</i></blockquote><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><br class=""></div><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">- Initializers are not guaranteed to be inherited. That's not weird for Swift. It's a little weird for Objective-C, but we already emit placeholders for non-inherited initializers to produce a runtime failure, which is what most NSCoder-bemoaners want anyway.</span><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><br class=""></div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;">- Methods taking 'Self' will silently accept the base type. If you override a conformance, you have to continue accepting the base type for these requirements, but that's just normal override rules.</div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><br class=""></div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;">- Overriding a conformance still doesn't let you change the associated types, even covariantly, because extensions to the base type may have used them in new positions. (Alternately, associated types and generic parameters are still invariant and we'd need a language feature to make them non-invariant.)</div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><br class=""></div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;">- Generic constraints will have to be taught to infer the base type.</div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><br class=""></div><blockquote class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; margin: 0px 0px 0px 40px; border: none; padding: 0px;"><div class="">foo(Subclass())<span class="Apple-converted-space"> </span><i class="">// calls foo<Base>(Subclass())</i></div></blockquote><blockquote class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; margin: 0px 0px 0px 40px; border: none; padding: 0px;"><div class=""><div class="">let obj: Subclass = bar()<span class="Apple-converted-space"> </span><i class="">// error, because bar<Base>() will return a Base</i></div></div></blockquote><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><div class=""><br class=""></div><div class="">- What does "subclass is Proto" do? What does "Subclass.self is Proto.Type" do? What does "Subclasses.instancesConformToProtocol(Proto.self)" do? My guess is 'true' for all three even though it's not exactly correct for Objective-C protocols with initializer requirements, but then what's the query that returns 'false'?</div><div class=""><br class=""></div><div class="">- Given all this, what benefit does required conformance bring? Just shorthand for making all the initializers required? (Which may be important if you got some of them through protocol extensions.)</div><div class=""><br class=""></div><div class="">Gosh. Maybe we<span class="Apple-converted-space"> </span><i class="">can</i> do it.</div><div class=""><br class=""></div><div class="">Jordan</div><div class=""><br class=""><div class=""><br class=""></div><div class=""><div class=""><div class=""><blockquote type="cite" class=""><div class="">On Dec 10, 2015, at 18:04, Joe Groff via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;">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:<div class=""><br class=""></div><div class="">- Rob Napier struggling to implement a `copy` method that works well with subclasses: <a href="https://twitter.com/cocoaphony/status/660914612850843648" class="">https://twitter.com/cocoaphony/status/660914612850843648</a></div><div class="">and making the observation that the interaction of protocol conformance and subtyping is very difficult to teach.</div><div class=""><br class=""></div><div class="">- Matt Bischoff trying to make Cocoa class clusters retroactively conform to his factory protocol:</div><div class=""><a href="https://twitter.com/anandabits/status/664294382774849536" class="">https://twitter.com/anandabits/status/664294382774849536</a></div><div class=""><br class=""></div><div class="">and Karl Adam trying to do the same:</div><div class=""><a href="https://gist.github.com/thekarladam/c3094769cc8c87bf55e3" class="">https://gist.github.com/thekarladam/c3094769cc8c87bf55e3</a></div><div class=""><br class=""></div><div class="">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.</div><div class=""><br class=""></div><div 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:</div><div class=""><br class=""></div><blockquote class="" style="margin: 0px 0px 0px 40px; border: none; padding: 0px;"><div class="">protocol Runcible {}</div></blockquote><blockquote class="" style="margin: 0px 0px 0px 40px; border: none; padding: 0px;"><div class="">class A: Runcible { }</div><div class="">class B { }</div><div class=""><br class=""></div><div class="">func foo<T: Runcible>(x: T) {}</div><div class=""><br class=""></div><div class="">foo(B()) // calls foo with T == A</div><div class=""><br class=""></div></blockquote><div class="">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:</div><div class=""><br class=""></div><blockquote class="" style="margin: 0px 0px 0px 40px; border: none; padding: 0px;"><div class="">protocol Fungible {</div><div class=""> init()</div><div class=""> static func funged() -> Self</div><div class="">}</div><div class=""><br class=""></div><div class="">class C: Fungible {</div><div class=""> init() {} // Non-required init is fine, since subclasses aren't directly Fungible</div><div class=""><br class=""></div><div class=""> // Non-Self return is fine too</div><div class=""> class func funged() -> C { return C() }</div><div class="">}</div><div class=""><br class=""></div></blockquote>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:<div class=""><br class=""></div><blockquote class="" style="margin: 0px 0px 0px 40px; border: none; padding: 0px;"><div class="">class D: C, override Fungible {</div><div class=""> // D must provide its own init()</div><div class=""> init() { super.init() }</div><div class=""><br class=""></div><div class=""> // D must override funged() to return D instead of C</div><div class=""> override class func funged() -> D { return D() }</div><div class="">}</div><div class=""><br class=""></div></blockquote>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:<div class=""><br class=""></div><blockquote class="" style="margin: 0px 0px 0px 40px; border: none; padding: 0px;"><div class="">class E: required Fungible {</div><div class=""> // init() must be required of all subclasses</div><div class=""> required init() { }</div><div class=""><br class=""></div><div class=""> // funged() must return a covariant object</div><div class=""> class func funged() -> Self { return Self() }</div><div class="">}</div><div class=""><br class=""></div></blockquote>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?<div class=""><br class=""></div><div class="">-Joe</div><img src="https://u2002410.ct.sendgrid.net/wf/open?upn=ZEz4qHYnXhPr3bBPu-2FxP4tN3HfWKL-2FtJpqkQ0gkOVSAD5nc-2BvRDekX6V6SNn-2FOenHH4Lxx2OoI14Py-2BWOuqOM1kNWiXKASB7c5PBQtP3C7ecE-2BJ2DHaXp3PpE0MSMkUjHAhwS1NTHnYIMgafzUfGWMl2ChvNI2F-2BunyTG-2BXj-2BWPGTANF5NPcwtcbZIl3A7FmCq-2BrBLWfHgw4nBAwvhoQisj7Ojt98C1mNQTvPUtl9t0-3D" alt="" width="1" height="1" border="0" class="" style="height: 1px !important; width: 1px !important; border-width: 0px !important; margin: 0px !important; padding: 0px !important;"></div>_______________________________________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a><br class=""><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br class=""></div></blockquote></div><br class=""></div></div></div></div><img src="https://u2002410.ct.sendgrid.net/wf/open?upn=9EwXyNl81W9TT3yZ17PL28-2Be7Ks-2FXLjqa0dZcsddi5YfC26FZhRdPsQO6I9Oj-2BZq6T4lHK9TUTal9lAsUzTmEzxCDKhbG2jiKAO-2BBOrreMxu5krGU0EGRrawTpSjxLuyLfaV6XTKYYOCsJJrtupcO4N-2B-2FqeWAC3DSErxmXal8bccUqTwdQyDdD0yxkHyvaL-2F85nk7sWU55lV8w5421rBlpdEgwOK0yXT7UWEhTZb3oY-3D" alt="" width="1" height="1" border="0" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; height: 1px !important; width: 1px !important; border-width: 0px !important; margin: 0px !important; padding: 0px !important;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class=""><span class="Apple-converted-space"> </span>_______________________________________________</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">swift-evolution mailing list</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><a href="mailto:swift-evolution@swift.org" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">swift-evolution@swift.org</a><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a></div></blockquote></div><br class=""></body></html>