> On Feb 20, 2017, at 4:17 PM, Jon Shier <j...@jonshier.com> wrote: > > Also possibly related is the covariance in protocol requirements. The > following example doesn’t compile without casting the arrays or single values > to the exact types required in the protocols, despite being covariant through > protocol conformance or subclass. > > protocol HasViews { > > var views: [UIView]! > > } > > protocol Updateable { } > > extension UIView: Updateable { } > > protocol HasProtocols { > > var updateables: [Updateable]! > > } > > class ViewController: UIViewController { > > @IBOutlet var views: [UIButton]! > @IBOutlet var updateables: [UIButton]! > > } > > extension ViewController: HasViews { } // fails without casting > extension ViewController: HasProtocols { } // fails without casting
This kind of thing we do want to support eventually, I think. Method overrides support a limited form of variance — you can make method parameters more optional in an override, or change their type to a base class; similarly a method return type can becomes less optional or change to a subclass. Overrides do not support converting to a protocol existential though. Protocol requirements do not support variance at all, except for @objc protocols, which allow the same optionality changes as method overrides (but no class upcasts!) This is all quite confusing to remember, and it would be great to see a proposal that makes the rules more general and consistent between method overrides in classes and protocol requirement witnesses. Slava > > > > Jon > > >> On Feb 20, 2017, at 7:07 PM, Howard Lovatt via swift-users >> <swift-users@swift.org <mailto:swift-users@swift.org>> wrote: >> >> 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 <mailto: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 >>> <mailto: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) >>> >>> <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 <mailto: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 <mailto:swift-users@swift.org> >>>> https://lists.swift.org/mailman/listinfo/swift-users >>>> <https://lists.swift.org/mailman/listinfo/swift-users> >>> >> >> _______________________________________________ >> swift-users mailing list >> swift-users@swift.org <mailto:swift-users@swift.org> >> https://lists.swift.org/mailman/listinfo/swift-users >> <https://lists.swift.org/mailman/listinfo/swift-users> >> -- >> -- Howard. >> _______________________________________________ >> swift-users mailing list >> swift-users@swift.org <mailto: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