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



Jon


> On Feb 20, 2017, at 7:07 PM, Howard Lovatt via swift-users 
> <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
> https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

Reply via email to