It is confusing in Swift what can be covariant and what is invariant, consider:
// Covarant arrays work class A {} class B: A {} let a = A() // A let b = B() // B var arrayA = [a] // Array<A> arrayA[0] = b // OK // And arrays of arrays var arrayArrayA = [arrayA] // Array<Array<A>> arrayArrayA[0][0] = b // OK let arrayB = [b] // Array<B> arrayArrayA[0] = arrayB // OK, works out that an Array<B> is a Array<A> // Covariant homebrew-collections work class C<T: AnyObject> { var e: T init(_ e: T) { self.e = e } } var cA = C(a) // C<A> cA.e = b // OK // But not quite for homebrew-collections of homebrew-collections var cCA = C(cA) // C<C<A>> cCA.e.e = b // OK let cB = C(b) // C<B> // cCA.e = cB // Error - cannot work out that a C<B> is a C<A> but can do so for arrays It is weird that the last line fails and the equivalent Array line doesn't. I suspect that there is some special typing going on for arrays, probably to make them play nice with Objective-C. However it would be simpler if everything was covariant when safe to be covariant, i.e. The last line should work. -- Howard. On Mon, 20 Feb 2017 at 8:38 pm, Isaac Rivera via swift-users < swift-users@swift.org> wrote: > I can see it is a (counter-intuitive) language design decision for type > safety… but then why, in the code below I can: > > class OtherThing: Something<UIViewController> { > override func start(_ completion: SomeCallback? = nil) { > // implementation details... > } > } > > let firstThing = OtherThing(viewController: UINavigationController()) > > OtherThing extends Something<UIViewController>… but I can instantiate it > with the subtype… > > Ok you will say, UINavigationController is a subtype of UIViewController, > but that still does not make Something<UINavigationController> a subtype > of Something<UIViewController>. > > Fair enough, but: > > let c1: Something<UIViewController> = Something(viewController: > UINavigationController()) > // c1 is of type "Something<UIViewController>" > > let c2 = Something(viewController: UINavigationController()) > // c1 is of type "Something<UINavigationController>” > > So it appears Something<UINavigationController> can be cast to type > Something<UIViewController>… > > Yet this is illegal? > > let somethings: [Something<UIViewController>] = [c1, c2] > > I dont know, something seems inconsistent. > > > On Feb 16, 2017, at 10:59 PM, Slava Pestov <spes...@apple.com> wrote: > > Hi Isaac, > > This is not about associated types. Rather, the issue is that a ‘Thing’ is > a ‘Something<UINavigationController>’, but you are casting it to > ‘Something<UIViewController>’. The two types are not related; in general, > if A is a subtype of B, then G<A> is not a subtype of G<B>. > > > https://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science) > > Slava > > On Feb 16, 2017, at 9:05 AM, Isaac Rivera via swift-users < > swift-users@swift.org> wrote: > > Hello, list! > > I am trying to find my way around Swift’s protocol limitations. It appears > that in general, any protocol with declared associatedtype will break > polymorphism? > > Take the case below which does not compile. All "Thing” instances are > "Something<VC: UIViewController>” but they can’t be passed around or > coerced as so. > > How is it that I can legally write the code: > > class Thing: Something<UINavigationController> { } > > and instantiate it, but it is not the very thing it implements? > > All Thing instances conform to the public interfaces of > Something<UIViewController> so why can’t they be recognized as such and > coerced as such? > > What is the work-around of this break in Polymorphism? > > import UIKit > > protocol Anything: class, NSObjectProtocol { > > associatedtype ViewControllerType: UIViewController > > var viewController: ViewControllerType { get } > > init(viewController: ViewControllerType) > > func addAnything(anything: Something<UIViewController>) -> Bool > } > > class Something<VC: UIViewController>: NSObject, Anything { > > typealias ViewControllerType = VC > > private(set) var viewController: ViewControllerType > > required init(viewController: ViewControllerType) { self.viewController = > viewController } > > final private var things = [String: Something<UIViewController>]() > > final internal func addAnything(anything: Something<UIViewController>) -> > Bool { > // implementation details... > return true > } > } > > class Thing: Something<UINavigationController> { } > > let firstThing = Thing(viewController: UINavigationController()) > let secondThing = Thing(viewController: UINavigationController()) > > firstThing.addAnything(anything: secondThing) > > // Playground execution failed: error: MyPlayground.playground:48:34: > error: cannot convert value of type 'Thing' to expected argument type > 'Something<UIViewController>' > > firstThing.addAnything(anything: secondThing as > Something<UIViewController>) > > // Playground execution failed: error: MyPlayground.playground:48:34: > error: cannot convert value of type 'Thing' to type > 'Something<UIViewController>' in coercion > > > > > _______________________________________________ > swift-users mailing list > swift-users@swift.org > https://lists.swift.org/mailman/listinfo/swift-users > > > > _______________________________________________ > swift-users mailing list > swift-users@swift.org > https://lists.swift.org/mailman/listinfo/swift-users > -- -- Howard.
_______________________________________________ swift-users mailing list swift-users@swift.org https://lists.swift.org/mailman/listinfo/swift-users