Subtyping forms a partial order.
- T is a subtype of T. (reflexivity)
- if T is a subtype of U and U is a subtype of T, then T = U (anti-symmetry)
- if T is a subtype of U and U is a subtype of V, then T is a subtype of V (transitivity)
Swift has subtyping for classes.
On the other hand, the implicit conversions for tuples don't have this behavior. A labelled tuple is implicitly convertible to an unlabelled tuple and vice-versa, but two labelled tuples are not implicitly convertible to each other (breaking transitivity) and the labelled and unlabelled types are not equal (breaking anti-symmetry).
// Multiple conversions are not permitted, breaking transitivity
let (x, y): (Int, Int) = (x: 10, y: 10) // OK
let (a: a, b: b) = (x, y) // OK
let (a: _, b: _) = (x: 10, y: 10) // error: cannot convert value of type '(x: Int, y: Int)' to specified type '(a: Int, b: Int)'
// Prints different types, breaking anti-symmetry
print(type(of: (a: 0, b: 0)), type(of: (0, 0)))
So yes, Swift does have both. What Swift doesn't have (and sometimes people ask for this, but I sure hope we don't implement it) is user-defined implicit conversions.
I misspoke about bridging conversions earlier (they don't happen with :), but (arguably) they do have counter-intuitive behavior -- naively you would expect that let y: T = x would be the same as let y = x as T when both compile but that's not the case.
let y = String() as NSString // OK
let z: NSString = String() // error
If you relax the idea a bit (to include as and not just :), then it would seem like String and NSString are subtypes of each other and hence equal (by anti-symmetry) but they're not equal (and hence interchangeable), they are "equal upto bridging".