It's worth noting that because generics are invariant in Swift, without any compiler magic, not even this would compile:
let newArray : [SuperClass] = A.arrayA
as you're attempting to convert an Array<A>
to an Array<SuperClass>
, which are entirely unrelated types (see this Q&A).
Although, for some native collection types in Swift (Array
being one of them), the compiler does do some magic which allows for implicit conversions between collections with elements of a subclass type to those with elements of a superclass type (as well as concrete types to abstract types that they conform to).
However, when it comes to this line:
let newArray : [SuperClass] = A.arrayA + B.arrayB
it's simply too much for the compiler to resolve, as it both has to locate the correct +
overload for the context, which could be any of the following:
public func +<C : RangeReplaceableCollection, S : Sequence where S.Iterator.Element == C.Iterator.Element>(lhs: C, rhs: S) -> C
public func +<C : RangeReplaceableCollection, S : Sequence where S.Iterator.Element == C.Iterator.Element>(lhs: S, rhs: C) -> C
public func +<RRC1 : RangeReplaceableCollection, RRC2 : RangeReplaceableCollection where RRC1.Iterator.Element == RRC2.Iterator.Element>(lhs: RRC1, rhs: RRC2) -> RRC1
and it has to infer that you want the element type for both A.arrayA
and B.arrayB
to be converted to SuperClass
.
In order to help it, you could simply cast both sides to [SuperClass]
:
let newArray = A.arrayA as [SuperClass] + B.arrayB as [SuperClass]
or do:
let newArray : [SuperClass] = A.arrayA as [SuperClass] + B.arrayB
Or (the most interesting solution), you could define an overload for +
that deals specifically with two Array<T>
operands:
func +<T>(lhs: [T], rhs: [T]) -> [T] {
var lhs = lhs
lhs.reserveCapacity(lhs.count + rhs.count)
lhs.append(contentsOf: rhs)
return lhs
}
(this has a similar implementation to the existing standard library overloads)
Now this works:
let newArray : [SuperClass] = A.arrayA + B.arrayB
From what I can tell, the compiler only has a problem when the generic constraint for the element types of the operands to be equal is secondary (i.e as a where
clause). This overload however has it as its primary constraint.