Wrote the following little test:
class Model { }
class SubModel : Model {}
class Collection<T: Model> {}
let collection = Collection<SubModel>()
var collections = [Collection]() // Also tried [Collection<Model>]()
collections.append(collection)
The compiler fails on the append call. The message is: 'SubModel' is not identical to 'Model'. Based on my experience in all other languages I have used with generics, this should work. As a Collection of type SubMode should always be coercible to a Collection of type Model. Anyone run into this? Workarounds?
This is happening because Swift does not support covariance in respect of generic type parameters.
For example:
class Animal {}
class Cat : Animal {}
Cat is clearly a subtype of Animal. However, this does not mean that, for instance, Array<Cat> is a subtype of Array<Animal>. In a language that supports covariance for generic type parameters, such as C#, Array<Cat> would be a subtype of Array<Animal>.
In your specific example, you can use a protocol and a non-generic Collection class to get around this limitation. Other situations might require more creativity.
protocol Collectible {}
class Model : Collectible {}
class SubModel : Model {}
class Collection {
func append(element: Collectible) {
// blah
}
}
var collection = Collection()
collection.append(Model())
collection.append(SubModel())
var collections = [collection]
Actually, in your case, you could just make the element of Collection be a Model, i.e., func append(element: Model), but I did it this way to stress that protocols can sometimes be used to get around covariance limitations.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With