14

How does covariance work for Optionals in Swift?

Say I write the following code:

var nativeOptionalView: Optional<UIView>
let button = UIButton()
nativeOptionalView = .Some(button)
var nativeOptionalButton = Optional.Some(button)

nativeOptionalView = nativeOptionalButton

It compiles and works just fine. However if I define MyOptional as

enum MyOptional<T> {
    case Some(T)
    case None
}

And write the following:

var myOptionalView: MyOptional<UIView>
let button = UIButton()
myOptionalView = .Some(button)
var myOptionalButton = MyOptional.Some(button)

myOptionalView = myOptionalButton

I get the error:

error: cannot assign value of type 'MyOptional<UIButton>' to type 'MyOptional<UIView>'

I understand why this errors happens with MyOptional, what I don't understand is why it doesn't happen with Optional.

fpg1503
  • 7,492
  • 6
  • 29
  • 49
  • 2
    I suspect the answer is "compiler magic". – jtbandes May 20 '16 at 17:05
  • 2
    I was afraid so :/ In that case, considering it's open source, where is that magic? – fpg1503 May 20 '16 at 17:12
  • Not sure; the codebase is pretty big. Starting point: https://github.com/apple/swift/search?utf8=%E2%9C%93&q=optional+covariant – jtbandes May 20 '16 at 17:13
  • 4
    If you're interested in learning about it, you might want to ask this question on the swift-dev mailing list. – jtbandes May 20 '16 at 17:59
  • 1
    I suspect this is the same behind the scenes magic that happens with array covariance, i.e assigning a `Array` to a `Array` – these appear to be the exceptions to the invariance of generics. – Hamish May 20 '16 at 19:57
  • There is a nice article written by Alexandros Salazar about Swift variance: https://nomothetis.svbtle.com/type-variance-in-swift – Cristik Jun 01 '16 at 06:45

2 Answers2

9

It doesn't. Swift does not support custom covariant generics for now.

The Swift type checker is per expression, not global (as in Haskell). This task is handled by the Semantic Analysis in lib/Sema. The constraint system then tries to match the types and special cases of covariance are then handled for collections, and optionals.

This was a language design decision. You should be able to do everything you need with the built-in collection types and optionals. If you aren't you should probably open a radar.

fpg1503
  • 7,492
  • 6
  • 29
  • 49
1

While I agree that there is probably some "compiler magic" going on, this can be accomplished in your custom implementation by casting the button to a UIView, e.g.

var myOptionalButton = MyOptional.Some(button as UIView)

or

var myOptionalButton: MyOptional<UIView> = .Some(button)
dalton_c
  • 6,876
  • 1
  • 33
  • 42