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

Slava Pestov spestov at apple.com
Thu Feb 16 21:59:55 CST 2017


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



More information about the swift-users mailing list