3

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?

1 Answer 1

6

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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.