Let me dwell on the comments of Antonov. The question is when can you use B for A. Usually you can do this when B is a subtype of A. For example, you can assign a UITableView
variable of type UIView
.
So, when is something a subtype of something else?
For classes, it's simple: if you are a subclass of B
from A
, B
is a subtype of A
For function types, you need to consider argument types and return type. The type of the function F2
is a subtype of the type of the function F1
, if the parameter types F2
s are supertypes of the parameter F1
s, and the type of the return type F2
is a subtype of the return type F1
s. You could say that a function should not require more (i.e., it does not require subtypes as parameters, but may require supertypes) and should not provide less (i.e., it should not return a supertype, but may return a subtype) , since its type is a subtype, the terminology is that the parameter types must be contravariant, and the return type must be covariant.
Example:
var f1: UIControl -> UIControl = ... let f2: UIView -> UIControl = ... let f3: UIControl -> UIButton = ... let f4: UIView -> UIButton = ... f1 = f2
Thus, types F2
, f3
and f4
are subtypes of type F1
s, while types f5
, f6
and f7
are not.
What about generic types? In Swift, custom types with type parameters are all invariant. That is, in your example, the Class1<T2>
object cannot be used as the Class1<T1>
object, regardless of the relationship between T1
and T2
(unless T1
and T2
are the same type).
However, Swift has some built-in dispersion rules that make your example work with arrays: [UITableView]
( Array<UITableView>
) is a subtype of [UIView]
( Array<UIView>
). Please note that the same is true for options, i.e. UITableView?
( Optional<UITableView>
) is a subtype of UIView?
( Optional<UIView>
). Thus, both arrays and additional modules are covariant with their type parameter.
Further reading: