Swiftの型の深淵をのぞく

> 深淵をのぞくとき、深淵もまたこちらをのぞいているのだ
> by フリードリヒ・ニーチェ

一緒に Swift の型の深淵をのぞいてみましょう。

継承と型の派生
------------------------

※ 以下、 _クラス_ と _継承_ 、 _is-a 関係_ について知っていることを前提とします。

`Animal` クラスと、それを継承した `Cat` クラスがあるとします。

```swift
class Animal {}
class Cat: Animal {}
```

このとき、 `Cat` は `Animal` を ___サブタイプ（ Subtype ）___ となるので、 `Animal` 型の変数に `Cat` のインスタンスを代入することができます（逆に、 `Animal` は `Cat` の ___スーパータイプ（ Supertype ）___ であると言います）。

```swift
let animal: Animal = Cat()
```

ここまでは何の変哲もない話です。

関数と型の派生
------------------------

※ 以下、 _クロージャ式_ と 関数の型 （  `() -> Foo` や `Bar -> ()` のような表記）について知っていることを前提とします。

さて、↑ではあえてサブクラスと言わずにサブタイプと言いました。なぜでしょう？型の派生はクラスでだけ起こるものではないからです。

### 戻り値の型と共変性

関数にも派生関係があります。たとえば、 `() -> Cat` は `() -> Animal` のサブタイプになります。

```swift
let getCat: () -> Cat = { Cat() }
let getAnimal: () -> Animal  = getCat
```

`Cat` が `Animal` のサブタイプであるため、 `Cat` を返す関数は常に `Animal` を返します。そのため、 `Cat` を返す関数は `Animal` を返す関数として振る舞えるのです（ `() -> Cat` は `() -> Animal` のサブタイプ）。

`Cat` が `Animal` のサブタイプであれば `() -> Cat` も `() -> Animal` のサブタイプとなることを戻り値の型について ___共変（ Covariant）___ であると言います。

### 引数の型と反変性

次に、引数について考えてみましょう。　`Cat -> ()` は `Animal -> ()` のサブタイプでしょうか？

```swift
let useCat: Cat -> () = { _ in }
let useAnimal: Animal -> () = useCat // コンパイルエラー
```

コンパイルエラーになってしまいました。なぜでしょう？もし、 `useCat` を `useAnimal` に代入できると、 `useAnimal` に代入された `useCat` に `Animal` が渡されてしまうかもしれません。 `useCat` は `Cat` しか受け取れないので、 `Animal` が渡せてしまうのはおかしいということになり、型エラーとなるわけです。つまり、 `Cat -> ()` は `Animal -> ()` としては振る舞えない（サブタイプではない）のです。

しかし、次のコードは OK です。

```swift
let useAnimal: Animal -> () = { _ in }
let useCat: Cat -> () = useAnimal
```

何が起こったのでしょう？ `Cat` は `Animal` のサブタイプなのに、 `useAnimal` を `useCat` に代入できるのは一見変な気がします。しかし、 `useCat` は `Cat` しか受け取らないので、 `useCat` に代入された `useAnimal` も `Cat` しか受け取ることはありません。 `Cat` は `Animal` のサブタイプなので `useAnimal` が `Cat` を受け取っても問題ないわけです。つまり、 `Animal` を受け取る関数は `Cat` を受け取る関数として振る舞えるのです（ `Animal -> ()` は `Cat -> ()` のサブタイプ、 `Cat -> ()` は `Animal -> ()` のスーパータイプ）。

`Cat` が `Animal` のサブタイプのとき、関係が反転して `Cat -> ()` が `Animal -> ()` のスーパータイプとなることを引数の型について ___反変（ Contravariant ）___ であると言います。

### 戻り値と引数をまとめる

戻り値の話と引数の話をまとめて考えると、次のような派生関係も考えることができます。

- `Cat -> Cat` は `Cat -> Animal` のサブタイプ
- `Animal -> Animal` は `Cat -> Animal` のサブタイプ
- `Animal -> Cat` は `Cat -> Animal` のサブタイプ

ジェネリクスと型の派生
------------------------

※ 以下、 _ジェネリクス_ について知っていることを前提とします。

Swift では部分的にしかサポートされていませんが、プログラミング一般にはジェネリクスも型の派生を作ります。

### ジェネリクスと共変性

ただ、値を入れて取り出せるだけの次のようなクラスを考えてみましょう[^1]。

```swift
class Box<T> {
    private let value: T
    init(value: T) { self.value = value }

    func get() -> T {
        return value
    }
}
```

`value` を `private` にしなければ `get` なんかいらないんですが、プロパティよりもメソッドで話をした方がわかりやすいので、あえて `get` メソッドを作って話を進めます。

このとき、 `Box<Animal>` と `Box<Cat>` の間に派生関係は生まれるでしょうか？

```swift
let catBox: Box<Cat> = Box(Cat())
let animalBox: Box<Animal> = catBox
let animal: Animal = animalBox.get()
```

`catBox` の `get` は `Cat` を、 `animalBox` の `get` は `Animal` を返します。 `animalBox` に代入された `Box<Cat>` の `get` は `Cat` を返しますが、 `Cat` は `Animal` のサブタイプなので `Box<Animal>` の `get` として振る舞う上で問題はありません。

`Box` には `get` 以外の公開されたメンバはないので、他に検討しなければならないものはありません。 `Box<Cat>` は `Box<Animal>` として振る舞うことができそうです。

`Cat` が `Animal` のサブタイプであれば `Box<Cat>` も `Box<Animal>` のサブタイプになることを、型パラメータ `T` について共変であると言います。関数の戻り値と似た話ですね。

一般的に、ジェネリックな型 `Foo<T>` があって、型パラメータ `T` がメソッドの戻り値にしか使われてない場合（引数に使われていない場合）、`Foo` は `T` について共変になります[^2]。

残念ながら、 __Swift 2.1 の時点では自作の型でこれを実現することができません__。しかし、 `Array` や `Optional` などの一部の標準ライブラリの型は、型パラメータについて共変になっています[^3]。

```swift
let catArray: Array<Cat> = [Cat(), Cat(), Cat()]
let animalArray: Array<Animal> = catArray
```

つまり、 `Array<Cat>` は `Array<Animal>` のサブタイプなわけです。同様に、 `Optional<Cat>` も `Optional<Animal>` のサブタイプです。

余談ですが、 C#, Scala, OCaml , Kotlin, Ceylon などの言語では型パラメータについての変性（共変、反変など）がサポートされています。その場合でも、型パラメータが戻り値でしか使われていないからといって自動的に共変になるわけではありません。次のように、型パラメータに明示的に修飾子（下記の例では `out` ）を付与し、もしその型パラメータが引数で使われたらコンパイルエラーとなります。

```kotlin
// Kotlin
class Foo<out T> { // T に out をつけると T について共変になる
    fun foo(): T { ... } // 戻り値でのみ T が使える
}
```

### ジェネリクスと反変性

同じように、ジェネリックな型 `Foo<T>` があって、型パラメータ `T` がメソッドの引数にしか使われてない場合（戻り値に使われていない場合）、`Foo` は `T` について反変になります。つまり、そのような `Foo` について、 `Foo<Cat>` は `Foo<Animal>` のスーパータイプになります。

共変の場合同様、残念ながら、 __Swift 2.1 の時点では自作の型でこれを実現することができません__。また、僕の知る限り、型パラメータについて反変になっている型は Swift に存在しません。

やはり共変のときと同じように、型パラメータについての変性がサポートされている言語でも、型パラメータが引数でしか使われていないからといって自動的に反変になるわけではありません。

```kotlin
// Kotlin
class Foo<in T> { // T に in をつけると T について反変になる
    fun foo(x: T) { ... } // 引数でのみ T が使える
}
```

Optionalと型の派生
------------------------

※ 以下、 _Optional type_ について知っていることを前提とします。

ここからようやく深淵に少し足を踏み入れるんですが、 `Optional` も型の派生を作ります。

```swift
let a: Int = 42
let b: Optional<Int> = a
```

上記のコードをそのまま解釈すれば、 `Optional<Int>` 型の変数に `Int` インスタンスを代入できているので `Int` は `Optional<Int>` のサブタイプだということになります。しかし、いくらなんでもこれは暗黙の型変換だろうと考えるのが普通です。

```swift
let a: Int = 42
let b: Optional<Int> = Optional(a) // 暗黙の型変換されていた箇所を明示的に書いた
```

しかし、実は Swift では `Int` は `Optional<Int>` のサブタイプです。それを示します。

戻り値についての共変性は、クラスの継承においても適用されます。つまり、メソッドをオーバーライドして、戻り値の型をサブタイプに変更しても構いません。

```swift
class A {
    func animal() -> Animal {
        return Animal()
    }
}

class B: A {
    // override して戻り値の型を Animal のサブタイプである Cat に変更
    override func animal() -> Cat {
        return Cat()
    }
}
```

上記のコードの `Animal` と `Cat` と同じことが `Optional<Int>` と `Int` でもできます。

```swift
class A {
    func foo() -> Optional<Int> {
        return nil
    }
}

class B: A {
    // override して戻り値の型を Optional<Int> のサブタイプである Int に変更
    override func foo() -> Int {
        return 42
    }
}
```

これができるとなると、暗黙の型変換というよりサブタイプであると解釈した方が自然です。

`Optional` は次のように宣言されていますが、同じような型を自作してもこんなことは実現できません。 `Optional` だけが特別なのです。

```swift
enum Optional<Wrapped> {
    case None
    case Some(Wrapped)
}

// 同じような型を自作しても Int は MyOptional<Int> のサブタイプにはならない
enum MyOptional<Wrapped> {
    case None
    case Some(Wrapped)
}
```

余談ですが、関連のある興味深い話として Union type があります。 Ceylon では `Integer|String` のように書くと `Integer` か `String` のどちらかを入れることのできる型を作ることができます。

```ceylon
// Ceylon
Integer a = 42;
Integer|String b = a;
```

この例でわかるように、 `Integer` は `Integer|String` のサブタイプです。そして興味深いのは、 Swift では `Int?` と書けば `Optional<Int>` のことですが、 Caylon では `Integer?` と書けば `Integer|Null` という Union type になることです。そのため、 Ceylon の `Integer` は `Integer?` のサブタイプになります。このサブタイピングは Swift の `Int` と `Int?` の関係と同じです。

Union type は、 Ceylon の他に、 TypeScript, Flow, Python の型ヒントなどで導入されています。特に、 Python の `Optional[Foo]` は `Union[Foo, None]` であるなど Ceylon そっくりです。

型の型と型の派生
------------------------

さて、前置きが長くなりましたがここからが本題です。

Swift では次のようにして型の型（メタタイプ）を得ることができます。

```swift
let intType: Int.Type = Int.self // Int の型を取得
let zero: Int = intType.init() // let zero: Int = Int() とするのと同じ
```

また、次のようにして、インスタンスからメタタイプを取得することもできます。

```swift
let n: Int = 42
let intType: Int.Type = n.dynamicType
```

### 継承の場合

さて、ここで `Animal` と `Cat` のメタタイプについて調べると面白いことがわかります。

```swift
let catType: Cat.Type = Cat.self
let animalType: Animal.Type = catType
```

なんと、 `Cat.Type` インスタンスを `Animal.Type` インスタンスに代入できました。これは、 `Cat.Type` は `Animal.Type` のサブタイプだということを意味しています。メタタイプは、元の型について共変なわけです。

では、これまでに見てきた継承以外のサブタイプのメタタイプを調べるとどうなるでしょうか。

### 関数の場合

関数のメタタイプは `(() -> Cat).self` などと書くとコンパイルエラーになってしまったので、 `dynamicType` を使って取得します。

```swift
let getCat: () -> Cat = { Cat() }
let voidToCatType: (() -> Cat).Type = getCat.dynamicType
```

さて、継承と同じであれば `voidToCatType` を `(() -> Animal).Type` 型の変数に代入できるはずです。

```swift
let voidToAnimalType: (() -> Animal).Type = voidToCatType // コンパイルエラー
```

```
error: cannot convert value of type '(() -> Cat).Type' to specified type '(() -> Animal).Type'
```

なんと！エラーになってしまいました。

`Animal -> ()` と `Cat -> ()` についても同様です。

```swift
let useAnimal: Animal -> () = { _ in }
let animalToVoidType: (Animal -> ()).Type = useAnimal.dynamicType
let catToVoidType: (Cat -> ()).Type = animalToVoidType // コンパイルエラー
```

```
error: cannot convert value of type '(Animal -> ()).Type' to specified type '(Cat -> ()).Type'
```

関数のメタタイプについては共変にならないようです。

### ジェネリクスの場合

次は、 `Array<Animal>` と `Array<Cat>` について調べましょう。

```swift
let catArrayType: Array<Cat>.Type = Array<Cat>.self
let animalArrayType: Array<Animal>.Type = catArrayType // コンパイルエラー
```

```
error: cannot convert value of type 'Array<Cat>.Type' to specified type 'Array<Animal>.Type'
```

ジェネリクスのメタタイプもダメでした。

### Optionalの場合

次は `Optional<Int>` と `Int` です。

```swift
let intType: Int.Type = Int.self
let optionalIntType: Optional<Int>.Type = intType // コンパイルエラー
```

```
error: cannot convert value of type 'Int.Type' to specified type 'Optional<Int>.Type'
```

`Optional` のメタタイプもダメでした。

### メタタイプの場合

次は `Animal.Type` と `Cat.Type` です。

```swift
let catTypeType: Cat.Type.Type = Cat.Type.self
let animalTypeType: Animal.Type.Type = catTypeType // コンパイルエラー
```

```
error: cannot convert value of type 'Cat.Type.Type' to specified type 'Animal.Type.Type'
```

メタメタタイプもダメでした。

補足
------------------------

※ 以下、 _値型_ と _参照型_ について知っていることを前提とします。

1. 継承
2. 関数
3. ジェネリクス
4. Optional
5. メタタイプ

これらのメタタイプの、元の型についての ___変性（Variance）___ を調べましたが、 1 のみ共変となっており、それ以外は共変でない（ ___非変（ Invariant ）___ な）という結果になりました[^4]。

実は上記の五つの中でサブタイプを作るか怪しいものがあります。それはジェネリクスです。

```swift
let catArray: Array<Cat> = [Cat(), Cat(), Cat()]
let animalArray: Array<Animal> = catArray
```

上記のコードを見ると、一見 `Array<Cat>` が `Array<Animal>` のサブタイプであるように見えます。しかし、僕はこれは暗黙の型変換なのではないかと疑っています（ `Int` を `Optional<Int>` に代入するときに暗黙の型変換のように思えるけど実はサブタイプになっていることと反対なのがおもしろいですね）。なぜなら、 `Array` は値型であるため、 `Array<Cat>` が `Array<Animal>` のように振る舞うなどという話以前に、代入時点でコピーされるからです[^5]。

つまり、実際には次のようになっているのではないかと考えられるわけです。

```swift
let catArray: Array<Cat> = [Cat(), Cat(), Cat()]
let animalArray: Array<Animal> = Array(catArray)
```

`Optional` のとき同様に、オーバーライドを使って検証してみましょう。

```swift
class A {
    func animals() -> Array<Animal> {
        return []
    }
}

class B: A {
    // override して戻り値の型を Array<Animal> のサブタイプである Array<Cat> に変更
    override func animals() -> Array<Cat> { // コンパイルエラー
        return []
    }
}
```

```
error: method does not override any method from its superclass
```

ダメでした。ますます怪しいです。ひとまず、 `Array` は型パラメータについて共変になっていてサブタイプを作るわけではなく、 `Array<Cat>` を `Array<Animal>` に代入できるのは暗黙の型変換と考えた方が良さそうです。

まとめ
------------------------

Swift のサブタイピングをまとめ、それらのメタタイプについての派生関係を調べました。

なぜか、継承関係にあるクラスのメタタイプ同士は共変になりましたが、その他のはサブタイプのメタタイプでは非変となってしまいました。

どうしてこんなことになってしまったのでしょうか。もしかすると、 Swift の型システムの深淵をのぞきすぎてしまったのかもしれません。

言い訳
------------------------

この投稿は Advent Calendar 用に 11 月に書き溜めてあったものです。その後、 Swift がオープンソース化され、型システムについて本気で調べるためにはコンパイラのソースを読まないといけなくなってしまいました。

現時点まではちゃんと読む時間を確保できておらず、また、年が明けたらしばらくは [try! Swift](http://blog.kishikawakatsumi.com/entry/2015/12/02/193302) の準備にかかりきりになりそうなので、このままお蔵入りしてしまいそうだったんですが、 [Swift その2](http://qiita.com/advent-calendar/2015/swift2) のカレンダーの最後の 3 日が投稿されなかったということで、急遽投稿することにしました。

コンパイラの中まで調べられてないのは心残りですが、お蔵入りするよりはマシかなぁとも思います。もしかすると後日（大分あとになるかもしれませんが）、ちゃんとコンパイラを読んだ上での調査結果を書くかもしれません。

------------------------

[^1]: Swift 1.2 の時代にはこの `Box` が[大活躍しました](https://github.com/robrix/Box)。

[^2]: より厳密なルールは[こちら](http://blogs.msdn.com/b/ericlippert/archive/2009/12/03/exact-rules-for-variance-validity.aspx)を御覧下さい。

[^3]: `Array` には型パラメータを引数にとる `append` のようなメソッドがありますが、それでも共変でいられる理由については[こちら](http://qiita.com/koher/items/81767a345d5ed53c04b7)を御覧下さい。

[^4]: 反変にもなっていませんでした。

[^5]: 実際には [Copy-on-Write](http://qiita.com/koher/items/47f444200d4e02b6414e) があるので代入時にコピーが走るわけではないですが、話の本質とは関係ありません。