Reputation: 3
I'm facing a problem I don't understand.
In my project, I want to make a collection of elements with some customised methods (like an update from a server). But when I try to group all these collections in an array, I get an error: "Cannot convert value of type MyCollection<someElement>
to expected argument type MyCollection<Any>
"
What I don't understand is that the same code with Array is working... Array isn't a collection?
// My collection which would contain an update method
class MyCollection<Element> {
var object:Element? = nil
}
let x = MyCollection<Int>()
var list = [MyCollection<Any>]()
list.append(x) //Cannot convert value of type 'MyCollection<In>' to expected argument type 'MyCollection<Any>'
let a = Array<Int>()
var lista = [Array<Any>]()
lista.append(a) //Doesn't get error at all...
I know I can do this with an array of the specific type but by grouping all of MyCollection in an array, I wish to use a code like :
func update() {
for e in list { // array of MyCollection<Any>
e.update()
}
}
Thank you in advance for your help ;)
Upvotes: 0
Views: 738
Reputation: 271625
Being able to convert from SomeType<Subtype>
to SomeType<Supertype>
is called covariance. In Swift, Array<T>
is covariant on T
by "compiler magic", and you can't do the same for your own types.
The type checker hardcodes conversions from Array to Array if there is a conversion from T to U. Similar rules exist for Optional and Dictionary. There's no mechanism for doing this with your own types.
Your own generic types are always invariant, meaning that there is never a conversion between SomeType<T>
to SomeType<U>
, as long as T
and U
are different types.
Let's imagine what would happen if the conversion on MyCollection
were allowed. You could do:
let myCollectionInt = MyCollection<Int>()
let myCollectionAny: MyCollection<Any> = myCollectionInt // suppose you can do this
myCollectionAny.object = "string" // myCollectionAny.object is of type Any?, so this should be ok
We've set myCollectionAny.object
to "string", but MyCollection
is a reference type, so myCollectionInt.object
should also be "string". But myCollectionInt.object
is an Int?
!
Of course this type-unsafety is also a problem with arrays, but the language designers have decided that casting arrays is a common enough thing to do, that disallowing it would do more hard than good.
Upvotes: 1