Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Storing generic objects in Swift Array

Tags:

generics

swift

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?

like image 484
John Bailey Avatar asked Jun 15 '26 19:06

John Bailey


1 Answers

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.

like image 107
Gregory Higley Avatar answered Jun 17 '26 09:06

Gregory Higley



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!