[swift-users] The case of broken polymorphism or "Cannot convert value of type to expected argument type"?

Isaac Rivera developer at isaacrivera.com
Mon Feb 20 03:37:20 CST 2017


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 <spestov at 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 at 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 at swift.org
>> https://lists.swift.org/mailman/listinfo/swift-users
> 

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-users/attachments/20170220/c55a2ec3/attachment.html>


More information about the swift-users mailing list