Swift 3.0で追加されそうなEitherについて

Swift 2.0 が今週にもリリースされそうというタイミングで気が早いですが、 Swift 3.0 （になるかわからないけど 2.0 の次の Swift ）で追加されそうな `Either` について説明し、どんなものになるか考えてみます。

次期 Swift で `Either` が追加されそうだというのは次のツイート[^1][^2]からです。

> @NachoSoto @jspahrsummers Didn't make it for WWDC, but we plan on having standard funcs for wrapping and releasing errors into an Either.

このツイートをした [Joe Groff](https://twitter.com/jckarter) さんは [Apple の Swift チームのメンバー](https://swift.org/community/#community-structure)です。

__本投稿では、 `Either` とは何か、 Swift に `Either` が追加されるとしたらどういうものになるか、どういう形が望ましいか考えてみたことを書きます。__（[英語でも簡単にまとめました。](https://gist.github.com/koher/abc04f7a03f9eb717787)）

Eitherとは
--------------------

まず初めに、 `Either` とは何かを簡単に説明します。

`Either` とはその名の通り「どちらか」を表す型です。例えば、 `Either<Int, String>` は `Int` か `String` の「どちらか」を表す型となります。

そんなものが何の役に立つのかと思うかもしれません。 __一番わかりやすい用途は、ある関数（やメソッド）が成功したら結果を、失敗したらエラー情報を返すような場合です。__ そのような場合には、 `Either` が結果かエラー情報かの「どちらか」を表す値となります。

### 実装

`Either` の実装は色々なバリエーションが考えられますが、概ね次のような感じになります。

```swift
enum Either<T, U> {
    case Left(T)
    case Right(U)
}
```

サードパーティの実装としては、 [robrix/Either](https://github.com/robrix/Either) や　[Swiftz および Swiftx の Either](https://github.com/typelift/Swiftx/blob/swift-development/Swiftx/Either.swift) 、 @gfx さんによる国産の [gfx/Swift-SwiftEither](https://github.com/gfx/Swift-SwiftEither) などがあります。

### 使い方

例として、得点が文字列で書かれていて、それをパースして整数に変換するケースを考えてみましょう（テキストフィールドにユーザーが入力した場合や、 CSV ファイルや XML ファイルに書かれている場合など、よくあるシチュエーションです）。得点は、最低点を　`0` 点、最高点を `100` 点とします。

`String` で与えられた得点を `Int` の得点に変換する関数 `toScore` を実装します。ただし、変換に成功した場合には `Int` を、失敗した場合にはエラー情報を返すようにしたいです。 `"abc"` のような文字列が与えられた場合や、たとえ整数としてパースできても `0` から `100` の範囲外であればエラーとします。

#### Stringでエラーメッセージを表す場合

ます、シンプルに失敗した場合は `String` でエラーメッセージを返すことにしてみましょう。エラーメッセージは、整数としてパースできたけど範囲外だった場合と、そもそも整数としてパースできなかった場合に分けるものとします。

なお、 `Either` をエラー処理に使う場合、 `Left` でエラーを、 `Right` で値を表すことが多いので、 `toScore` の戻り値の型は `Either<String, Int>` となります。以下、本投稿ではすべてエラーを前に書くスタイルで統一しますが、 Swift に追加される `Either` がそうなるかはわかりません。

```swift
func toScore(string: String) -> Either<String, Int> {
    switch Int(string) {
    case .Some(let score) where 0...100 ~= score: // 成功
        return .Right(score)
    case .Some(let score): // 失敗：整数としてパースできたが範囲外の場合
        return .Left("Out of range: \(score)")
    case .None: // 失敗：整数としてパースできなかった場合
        return .Left("Failed to parse as an integer: \"\(string)\"")
    }
}
```

上記のコードの簡単な説明は下記です。

- `Int(string)` で `String` を `Int` に変換
- `Int` の `init(_ text: String)` は _Failable Initializer_ なのでパースに失敗すると `nil` を返す（戻り値は `Int` ではなく `Int?` ）
- `switch` 文のパターンマッチで場合分けして値を返す

これを使うコードは次のようになります。

```swift
let result: Either<String, Int> = toScore("42")

switch result {
case .Left(let errorMessage):
    // エラー処理
    print(errorMessage)
case .Right(let score):
    // score を使った処理
    ...
}
```

#### ErrorTypeでエラーを表す場合

エラーメッセージを直接 `Either` で扱うのは良いアイデアではありません。

例えば、エラーメッセージを多言語化する場合を考えて下さい。 `toScore` の中にすべてのエラーメッセージを実装しようとすると `toScore` がどんどん肥大化してしまいます。 `toScore` のロジックを実装する人と、エラーメッセージを実装する人は別の人かもしれません。役割を明確化し、 `toScore` はエラーメッセージそのものを返すよりもエラーの原因を特定できるだけの情報を返すに留めておいた方が良いでしょう。エラーメッセージを実装する人は、その情報を使って実装すれば良いのです。

せっかく Swift 2.0 で `ErrorType` が追加されたので、ここではエラー情報を `ErrorType` として実装してみましょう。

まず、 `toScore` が整数のパースには成功したものの、範囲外になってしまった場合を考えます。この場合は、範囲外になってしまったことに加えて、一体その整数が何だったのかをエラー情報として保持したいです。

次に、そもそも与えられた文字列を整数としてパースできなかった場合には、パースに失敗したことに加えて、その文字列が何だったのかをエラー情報として保持したいです。

これをまとめると、次のような実装になります。

```swift
enum ScoreFormatError: ErrorType {
    case OutOfRange(Int) // 整数としてパースできたが範囲外の場合
    case NotInteger(String) // 整数としてパースできなかった場合
}
```

これを使うと `toScore` は次のようになります。

```swift
func toScore(string: String) -> Either<ScoreFormatError, Int> {
    switch Int(string) {
    case .Some(let score) where 0...100 ~= score: // 成功
        return .Right(score)
    case .Some(let score): // 失敗：整数としてパースできたが範囲外の場合
        return .Left(.OutOfRange(score))
    case .None: // 失敗：整数としてパースできなかった場合
        return .Left(.NotInteger(string))
    }
}
```

`toScore` を使うコードは次のようになります。

```swift
let result: Either<ScoreFormatError, Int> = toScore("42")

switch result {
case .Left(.OutOfRange(let score)):
     // このように score の値でエラーメッセージを出し分けるのも簡単
    if score < 0 {
        print("値が小さすぎます: \(score)")
    } else {
        print("値が大きすぎます: \(score)")
    }
case .Left(.NotInteger(let string)):
    print("整数ではありません: \(string)")
case .Right(let score):
    // score を使った処理
    ...
}
```

### Optionalとの比較

`Either` と似た型として `Optional` があります。

`Optional` はこれまで、 Swift の標準ライブラリで成功か失敗かを表す型として使われてきました。例えば、 _Failable Initializer_ の戻り値は　`Optional` で、失敗したときに `nil` を返します。

```swift
let number: Int? = Int("42") // パースに失敗したら　nil
```

`Either` を成功か失敗かを表す型として使う場合、 `Optional` の違いは __エラー情報を含むことができるかどうか__ です。

例えば、 [SwiftyJSON](https://github.com/SwiftyJSON/SwiftyJSON) は `Optional` を多用していますが、次のようなケースで `nil` が返って来たときにその原因を知ることはできませんでした。

```swift
let json: JSON = JSON(data: data)
let bar: Int? = json["foo"]["bar"].int
```

`bar` が `nil` だった場合、次のような理由が考えられます。

 -  JSON に `"foo"` という要素がなかった
 - `"foo"` はあったけど `"bar"` がなかった
 - `"bar"` もあったが `Int` ではなかった
 - そもそも JSON のパースに失敗した

しかし、 `nil` から上記のいずれであるかを知ることはできません。失敗の原因がわかればデバッグがはかどりますし、原因によって処理を変えることもできます（ユーザーに提示するメッセージを出し分けるとか、 `"bar"` がなかった場合だけデフォルト値に置き換えるとか）。

`String` を `Int` に変換するというように失敗の原因が明らかなときは `Optional` で十分ですが、様々な原因が考えられる場合には `Either` であってほしいところです。

### モナドとしてのEither

`Optional` 同様、 `Either` も ___モナド___ として実装されることが多いです。つまり、 `map` や `flatMap` を持つということです。

- ["SwiftのOptional型を極める"](http://qiita.com/koher/items/c6f446bad54442a28bf4)
- ["モナドについてSwiftで説明してみた"](http://qiita.com/koher/items/12f72f2fc2db7fa709cf)

`Either` が _モナド_ であることで `Optional` 同様 `map` や `flatMap` を使って便利に取り回すことができます。

```swift
let score1: Either<ScoreFormatError, Int> = toScore("42")
let score2: Either<ScoreFormatError, Int> = toScore("97")

// Either に包んだまま score1 の得点の二乗を計算
let square: Either<ScoreFormatError, Int> = score1.map { $0 * $0 }

// Either に包んだまま score1 と score2 の平均を計算
let mean: Either<ScoreFormatError, Int> = score1.flatMap { s1 in score2.flatMap { s2 in .Right((s1 + s2) / 2) } }
```

`Either` の `map` や `flatMap` は次のように実装できます[^3]。あと、 _モナド_ の条件である、値を包むだけの _イニシャライザ_ も併せて実装します。

```swift
extension Either {
    init(_ value: U) {
        self = .Right(value)
    }

    func map<V>(transform: U -> V) -> Either<T, V> {
        return flatMap { .Right(transform($0)) }
    }

    func flatMap<V>(transform: U -> Either<T, V>) -> Either<T, V> {
        switch self {
        case .Left(let left):
            return .Left(left)
        case .Right(let right):
            return transform(right)
        }
    }
}
```

### do-try-catchとの比較

#### Eitherとdo-try-catchの類似性

`Either` ができることは _do-try-catch_ とほぼ同等です。

例として、 `toScore` を _do-try-catch_ で実装してみましょう。

```swift
func toScore(string: String) throws -> Int {
    switch Int(string) {
    case .Some(let score) where 0...100 ~= score: // 成功
        return score
    case .Some(let score): // 失敗：整数としてパースできたが範囲外の場合
        throw ScoreFormatError.OutOfRange(score)
    case .None: // 失敗：整数としてパースできなかった場合
        throw ScoreFormatError.NotInteger(string)
    }
}
```

```swift
do {
    let score = try toScore("42")

    // score を使った処理
    ...
} catch ScoreFormatError.OutOfRange(let score) {
    if score < 0 {
        print("値が小さすぎます: \(score)")
    } else {
        print("値が大きすぎます: \(score)")
    }
} catch ScoreFormatError.NotInteger(let string) {
    print("整数ではありません: \(string)")
}
```

`Either` 版のコードと同じことができているのがわかると思います。

#### 現状のSwiftにおけるdo-try-catchの問題

ただし、将来的には解消されると思いますが（というかされてほしい）、 Xcode 7 beta 6 の時点では、トップレベルスコープ以外で上記のコードを実行すると、 `catch` が網羅的でないとして次のようなコンパイルエラーになります。

```
Errors thrown from here are not handled because the enclosing catch is not exhaustive
```

Java と違って Swift の `throws` 句にはエラーの型を記述することができないので、関数やメソッドが `throw` し得るエラーの型を特定することができません。初めは推論されるのかと思っていましたが、どうも今のところそういうわけではなさそうです。もしこのままの仕様であれば次のようなコードとなり、タイプセーフを重視している Swift が台無しなのでどうにかしてほしいところです。個人的には、面倒でも `throws` 句に型が記述できるようになるのがいいと思います（推論はあってもいいけど、実装を変更しただけでシグネチャが勝手に変わるのは微妙）。

```swift
do {
    let score = try toScore("42")

    // score を使った処理
    ...
} catch ScoreFormatError.OutOfRange(let score) {
    ...
} catch ScoreFormatError.NotInteger(let string) {
    ...
} catch {
    // ここには絶対に到達しないが毎回これを書かないといけない
    fatalError("Never reaches here.")
}
```

最後の `catch` 節は本来不要なのにコンパイルを通すために必須というのは面倒ですし、誤ってその他のエラーを `throw` してしまうとクラッシュしてしまいます。これまでのタイプセーフな Swift を踏襲して、コンパイル時に型の制約でそのような事態を防げることが望まれます。

#### Eitherとdo-try-catchとの使い分け

話がそれましたが、 `Either` と _do-try-catch_ で表現できることが変わらなくても、 `Either` で失敗を扱うことで次のような利点があります。

- 失敗を値として取り回せるので、その場で処理をする必要がない
- `map` や `flatMap` を使ったり、後述の便利な構文を使うことができる（ `!` 一つでエラーを無視するとか）
- 関数型のスタイルと相性がいい

一方で、 `Either` にはできないこともあります。それは、 ___副作用___ を持つ（戻り値を返すだけでなく状態を書き換える）関数やメソッドにエラー処理を強制することができないことです。

```swift
func setScore(score: Int) throws {
    switch score {
    case 0...100:
        self.score = score // 副作用
    default:
        throw OutOfRangeError(range: 0...100, value: score)
    }
}
```

上記の `setScore` を使う場合にはエラー処理を強制できますが、 `Either` ではそれができません。無理やり `Either` で書くなら

```swift
func setScore(score: Int) -> Either<OutOfRangeError, Void>
```

となりますが、これなら `Optional` の方がスマートです。

```swift
func setScore(score: Int) -> OutOfRangeError?
```

いずれにせよ、戻り値を無視されれば（もしくは忘れていたら）エラーが無視されてしまいます。

ちなみに `Either` は元々関数型言語で使われていたものですが、純粋関数型言語ではそもそも副作用が存在しないのでそのような問題も存在しません。

以上をまとめると、次のような指針で `Either` と　_do-try-catch_ を使い分けるのが良いでしょう。

- 副作用がない関数やメソッドでは `Either` を使う
- 副作用がある関数やメソッドでは _do-try-catch_ を使う

#### do-try-catchのEitherへの変換

このように、　_do-try-catch_ ではなく `Either` でエラー処理をしたいニーズがあるため、冒頭の Groff さんのツイートにつながります。 Groff さんが言っているのは、 `throws` 付きの関数（やメソッド）をコールするときに、それを _do-try-catch_ で扱うのではなく、代わりに `Either` でラップして受け取れるようにする関数を標準ライブラリに追加するという話だと思います。

仮にこの関数を __`either` 関数__ と呼ぶことにしましょう。 `either` 関数は次のように実装できます。

```swift
func either<T, U>(@autoclosure f: () throws -> U) -> Either<T, U> {
    do {
        return .Right(try f())
    } catch let error as T {
        return .Left(error)
    }
}
```

この関数のキモは `@autoclosure` です。 `@autoclosure` によって、この関数は次のように `try` 演算子を使った式を囲んで使うことができます。

```swift
let result: Either<ScoreFormatError, Int> = either(try toScore("42"))
```

なお、前述の `throws` の型が特定されない問題があるので実際には次のように書かなければコンパイルエラーになってしまいます。

```swift
func either<T, U>(@autoclosure f: () throws -> U) -> Either<T, U> {
    do {
        return .Right(try f())
    } catch let error as T {
        return .Left(error)
    } catch {
        fatalError("Never reaches here.")
    }
}
```

どんな仕様が採用されるか
--------------------

一般的には前節で見たようなものを `Either` と言いますが、 Swift の `Either` がそのような仕様になるとは限りません。例えば、 Swift では一般的に _ラムダ式_ や _匿名関数_ などと呼ばれるものを _クロージャ_ と呼んでおり、他の言語における _クロージャ_ と意味合いが違います。

そのように、同じ名前のものが言語間で少しずつ異なるということはよくあることです。前節で挙げた `Either` の実装の他に、 Swift の `Either` として採用されそうなものを挙げてみます。

### Result

現在 Swift で `Either` 的なものとしてデファクトになっているのが [antitypical/Result](https://github.com/antitypical/Result) です。

前節で `Either` の一番わかりやすい用途は、ある関数（やメソッド）が成功したら結果を、失敗したらエラー情報を返すような場合だと書きましたが、それならはじめから片方はエラー情報にしてしまうおうと考えたのが `Result` です。 __`Result` は成功か失敗かに特化した `Either`__ と考えることができます。

`Result` の実装をシンプルにすると次のような感じです。

```swift
enum Result<T, Error: ErrorType> {
    case Success(T)
    case Failure(Error)
}
```

これを使って `toScore` を実装すると次のようになります。 `Left` が `Failure` に、 `Right` が `Success` に変わっただけです。成功か失敗かのために `Either` を使う分には `Result` と変わりません。

```swift
func toScore(string: String) -> Result<Int, ScoreFormatError> {
    switch Int(string) {
    case .Some(let score) where 0...100 ~= score: // 成功
        return .Success(score)
    case .Some(let score): // 失敗：整数としてパースできたが範囲外の場合
        return .Failure(.OutOfRange(score))
    case .None: // 失敗：整数としてパースできなかった場合
        return .Failure(.NotInteger(string))
    }
}
```

この `toScore` を使うコードも `Either` のときとほとんど変わらないので省略します。

Groff さんのツイートでは `Either` についてエラー処理の文脈で言及しているので、 __Swift の `Either` は `Result` のようにエラー処理専用の型となる可能性も考えられます__。

また、 Swift が大きな影響を受けた言語 [Rust](https://www.rust-lang.org/) の標準ライブラリには [Result](https://doc.rust-lang.org/std/result/) があり、 Swift でも `Either` ではなく `Result` という名前で追加される可能性もあると思います。

### タプル & Optional

`Either` 代わりのお手軽な代替手段として用いられることが多いのがタプルと `Optional` の組み合わせです。 `Either<T, U>` を `(T?, U?)` または `(left: T?, right: U?)` として表すのです。 `T` が値を持つときは `U` を `nil` に、 `U` が値を持つときは `T` を `nil` にすることで `Either` のようなことができます。 [Go 言語](https://golang.org/)ではよくこれと似たような方法が採られます。

この方法だと `toScore` は次のように実装できます。

```swift
func toScore(string: String) -> (ScoreFormatError?, Int?) {
    switch Int(string) {
    case .Some(let score) where 0...100 ~= score: // 成功
        return (nil, score)
    case .Some(let score): // 失敗：整数としてパースできたが範囲外の場合
        return (.OutOfRange(score), nil)
    case .None: // 失敗：整数としてパースできなかった場合
        return (.NotInteger(string), nil)
    }
}
```

これなら __新しく Swift の標準ライブラリに `Either` を追加しなくても、戻り値として `(T?, U?)` を持った `either` 関数を追加するだけで済ませられます__。

しかし、僕は __この方法は望ましくない__ と思います。この方法には致命的な欠陥があります。それは、 __`(T?, U?)` は型として `T` か `U` のどちらかだけが値を持つことを保証しない__ ということです。 `T` も `U` も値を持つかもしれませんし、両方 `nil` かもしれません。関数の仕様として、必ずどちらかが値を持ちどちらかは `nil` と決めてしまうことはできても、それはタイプセーフな Swift の考え方とはマッチしません。

例えば、上記の　`toScore` を使おうとすると次のようなコードを書かなければなりません。

```swift
let result: (ScoreFormatError?, Int?) = toScore("42")

switch result {
case (let error, nil):
    // エラー処理
    ...
case (nil, let score):
    // score を使った処理
    ...
default:
    // ここには絶対に到達しないが毎回これを書かないといけない
    fatalError("Never reaches here.")
}
```

最後の `default` 節は不要なのにコンパイルを通すために必須ですし、万が一どちらも値が入ってしまったりどちらも　`nil` になった場合はクラッシュしてしまいます。コンパイル時に型の制約でそのような事態を防げる `Either` や `Result` の方が優れていると言えるでしょう。

### Failable

Swift の `Either` は `Result` をさらにシンプルにし、 @kanotomo さんの ["Swift 2でエラーをthrowする関数からEitherを作る"](http://qiita.com/kanotomo/items/f0e5c67d0d1c1366ae4a) の中で述べられている `Failable` のような実装になるかもしれません。

```swift
enum Failable<T> {
    case Success(T)
    case Failure(ErrorType)
}
```

この `Failable` は `Failure` が取れる値を汎用的な `ErrorType` とすることで、 `Result` から第二の型パラメータを消したものです。型パラメータが一つになるので見た目にはすっきりします。

```swift
func toScore(string: String) -> Failable<Int> {
    ... // 実装は同じなので省略
}
```

しかし、エラーの型情報が消えてしまっているため、利用時には面倒ですしタイプセーフではありません。"タプル & Optional" の項で述べたのと同じ状況です。

```swift
let result: Failable<Int> = toScore("42")

switch result {
case .Failure(ScoreFormatError.OutOfRange(let score)):
    print("値が範囲外です: \(score)")
case .Failure(ScoreFormatError.NotInteger(let string)):
    print("整数ではありません: \(string)")
case .Success(let score):
    // score を使った処理
    ...
default:
    // ここには絶対に到達しないが毎回これを書かないといけない
    fatalError("Never reaches here.")
}
```

標準ライブラリに `Failable` 相当の　`Either` を追加しなければならず、しかもタイプセーフでもないのであれば、このような `Either` にする理由がないように見えます。

しかし、このような仕様になるかもしれないと僕が思うのは、 "現状のSwiftにおけるdo-try-catchの問題" で述べたように、現状では `throws` がついた関数（やメソッド）はすべて汎用的な `ErrorType` を `throw` することになっているようだからです。

__関数が `throw` するものが汎用的な `ErrorType` なら、 `either` 関数が返す `Either` のエラーの型を決定することができません。もしこのままの仕様が続くようであれば、 `either` 関数の戻り値として採用される `Either` が `Failable` 相当のものになる可能性もあるでしょう。__

__そのようなことになるのは望ましくない__ です。 `throw` されるエラーの型が推論されるようにするか、 `throws` 句で型を記述できる仕様にしてほしいところです。


なお、本項で述べた `Failable` のようなものを一般的に `Failable` と呼ぶかはわかりません。僕も ["Swift 2.0 の try, catch ファーストインプレッション"](http://qiita.com/koher/items/0c60b13ff0fe93220210) の中で `Failable` を作っていますがこれは `Result` 相当のものでしたし、 `Failable` と名付けたのは `Optional` と語感や形容詞であることをそろえたかったのと、 _Failable Initializer_ という用語から考えても適切な名前だろうと考えたからです。 @kanotomo さんがどういう意図で `Failable` と名付けたのかや、一般的に `Failable` と呼ばれるものがあるのかはわかりません。

### Union Type （直和型）

Swift 以外の言語に目を向ければ、 `Either` と似たものに ___Union Type___ があります。

_Union Type_ とは多くの場合 `T|U` のように書かれる型で、 `T` か `U` のどちらかを表します。そう書くとまさに `Either` と同じように思えますが次のような違いがあります。

まず、 _Union Type_ では `T` や `U` が `T|U` の派生型として扱われるため、 `T` や `U` のインスタンスを直接 `T|U` 型の変数に代入することができます。

```swift
let union: Int|String = 42 // OK
// let either: Either<Int, String> = 42 // コンパイルエラー
let either: Either<Int, String> = .Left(42) // Either で包む必要あり
```

一方で、その裏返しとして `Int|Int` は `Int` と同じものになってしまい `Either<Int, Int>` でなら表せるものが表せません[^4]。

```swift
let union: Int|Int = 42 // 左と右の Int を区別できない
let either1: Either<Int, Int> = .Left(42) // 左の Int
let either2: Either<Int, Int> = .Right(42) // 右の Int
```

__Swift には _Union Type_ はありませんが、 [TypeScript](http://www.typescriptlang.org/) や [Ceylon](http://ceylon-lang.org/) 、 [Flow](http://flowtype.org/) で採用されるなど最近のプログラミング言語のトレンドなので、次期 Swift で追加されるかもしれません。__ その場合、 `either` 関数の戻り値の型は _Union Type_ `T|U` で表される可能性が高いでしょう。

_Uniton Type_ を使えば、 `toScore` は次のように書けます。戻り値を `Either` で包む必要がないのでとてもシンプルです。

```swift
func toScore(string: String) -> ScoreFormatError|Int {
    switch Int(string) {
    case .Some(let score) where 0...100 ~= score: // 成功
        return score
    case .Some(let score): // 失敗：整数としてパースできたが範囲外の場合
        return .OutOfRange(score)
    case .None: // 失敗：整数としてパースできなかった場合
        return .NotInteger(string)
    }
}
```

使うときは次のようになります。こちらもシンプルです。

```swift
let result: ScoreFormatError|Int = toScore("42")

switch result {
case .OutOfRange(let score):
    print("値が範囲外です: \(score)")
case .NotInteger(let string):
    print("整数ではありません: \(string)")
case let score as Int:
    // score を使った処理
    ...
}
```

これはタイプセーフですし、シンプルという点では素晴らしいです。ただ、個人的には __Swift の文化とはなじまない__ ように思います。 `Optional` との整合性なども考えると、やはり `enum` で　`Either` を実装する方が Swift らしく、一貫性があるでしょう。

ただし、次節で述べるように、 `Either` を `enum` で実装しながらも _Union Type_  っぽく振る舞わせるのはありだと思います。

Either の言語レベルでの特別なサポート
--------------------

ただ `Either` を導入するだけならライブラリを入れなくていいというだけで、使い勝手は大きくは変わりません。標準ライブラリでサポートするからには `Optional` のように便利な手段を色々と提供してほしいものです。

### 型の記述のシンタックスシュガー

正直、 `Either<Foo, Bar>` などと記述するのは面倒です。 `Optional<Foo>` を `Foo?` 、 `Array<Foo>` を　`[Foo]` 、　`Dictionary<Foo, Bar>` を　`[Foo: Bar]` と記述できるのと同じように、　`Either` にも型を記述する際の便利なシンタックスシュガーがほしいです。

その候補として、僕は _Union Type_ の項で見たような `Foo|Bar` という記法で書けるのがいいんじゃないかと思います。シンプルでわかりやすく書きやすいですし、意味的にも _Union Type_ との共通点があります。他の言語で _Union Type_ が記述できてることからも、コンパイラがコードをパースする上での問題も少なそうです。

これは、 `Either` を _Union Type_ で表そうということではなくて、 `Optional` の実体が `Optional<T>` という `enum` だけど `T?` の形で書けるように、 `Either` も実体は `Either<T, U>` という `enum` だけど `T|U` の形で書けるようにしようということです。

なお、この場合　`Foo|Bar|Baz` が `Either<Either<Foo, Bar>, Baz>` となるか `Either<Foo, Either<Bar, Baz>>` となるか（つまり、 `|` が左結合か右結合か）は検討の余地があります。 `ErrorA|ErrorB|Int` のような使い方が多いのであれば前者の方が便利ですし、 `Error|Int|String` のような使い方が多いのであれば後者の方が便利です（ `map`, `flatMap` する場合や、後述の _Either Chaining_, _Forced Unwrapping_, `??` 演算子などを使う場合を考えて）。 `Either` のエラーを後ろに書くスタイルの場合、議論がすべて反転するので気を付けて下さい。いずれにせよ `(Foo|Bar)|Baz` のように結合の優先順位を指定できる必要があるでしょう。

___（追記: 2015-12-08 ） Swift がオープンソース化されたので、試しに `Int|String` のような構文が使えるように[コンパイラを改造してみました](http://qiita.com/koher/items/aea1b44d0aef43b0059c)。___

### 暗黙の型変換

`Optional` は `enum` でありながら次のような代入が可能です。

```swift
let a: Int? = 42
```

これは本来であれば次のように書かなければならないはずです。

```swift
let a: Int? = .Some(42)
```

`Int` と `Int?` は別の型であり、本来的には直接代入することはできません。これができるということは、 `Int` から `Int?` への ___暗黙の型変換___ が行われたということです。シンタックスシュガーを使わず次のように書けばその違和感に気付くと思います。

```swift
let a: Optional<Int> = 42 // Optional<Int> に Int を代入
```

暗黙の型変換は様々な問題を引き起こしやすく、 Swift では暗黙の型変換は厳しく取り締まられています。初期の Swift から Swift 1.0 になる過程で暗黙の型変換を定義する文法は削除されましたし、 `Float` から `Double` など、他の多くの言語で認められているようなものでも暗黙の型変換が認められていません。さらに、 Swift 1.2 では `String` と `NSString` などの間の暗黙の型変換も禁じられました。

そのような中で `Optional` の例外扱いは特別なものです。さすがに `Optional` で暗黙の型変換を禁止するとコードを書くのが面倒すぎるということなのでしょう。

`Either` は `Optional` の兄弟のようなものなので、 `Either` においても、暗黙の型変換が適用されれば使い勝手が良くなるのではないかと思います（ただ、前述のように暗黙の型変換は問題を起こしやすいので、本当にそれがいいかはわかりません）。

```swift
let a: Either<Int, String> = 42 // 明示的に Either に包む必要がない
```

これと `Foo|Bar` のようなシンタックスシュガーが組み合わされば、 `Either` は `enum` でありながら相当 _Union Type_ っぽく振る舞えることになります。

```swift
let a: Int|String = 42 // Union Type っぽい
```

### Subtyping

`Optional` にはさらに驚くべき特別扱いがあります。なんと、 __`Int` は　`Int?` の派生型として扱われるのです__。これはどのようにすれば確かめられるでしょう？

次のように書いても、前項で書いたように暗黙の型変換だと考えることができます。

```swift
let a: Int? = 42
```

しかし、次のコードがコンパイルできることは暗黙の型変換で説明することはできません。

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

class B: A {
    // override して戻り値の型を Int に変更
    override func foo() -> Int {
        return 42
    }
}
```

`foo` の戻り値の型に注目して下さい。元々 `Int?` だったのが、オーバーライドされたときに `Int` に変更されています。

一般的に、オブジェクト指向言語では継承してメソッドをオーバーライドするときに時に戻り値の型を狭める（派生型にする）ことができます。これは、 `Animal` を返すメソッドをオーバーライドして `Cat` を返すようにしても、 `Cat` は `Animal` なのでスーパークラスとしてインスタンスを扱っているときにも常に `Animal` を返していることになり何も困らないからです。

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

class B: A {
    // override して戻り値の型を Cat に変更
    override func bar() -> Cat {
        return Cat()
    }
}

let b: B = B()
let a: A = b

// b の　bar() が呼ばれ Cat が返るが Animal として振る舞える
let animal: Animal = a.bar()
```

前述の `foo` のケースも、　`Int?` を `Animal` に、 `Int` を `Cat` に読みかえれば全く同じ関係になっているのがわかると思います。つまり、 Swift では `Int` は `Int?` の派生型なのです。

`Optional` は次のような `enum` です。

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

しかし、同じような `enum` を作っても `Optional` のような派生関係は生まれませんし、それを実現する構文も今のところありません。 `Int` が `Int?` になるのは、 `Optional` だけに与えられた特別な仕様なのです。

これは、前項で挙げた暗黙の型変換が `Optional` だけに許されている理由の説明にもなります。つまり、 __暗黙の型変換が行われているのではなく、型に派生関係があるので代入できているだけと解釈することができるのです__。

同じことを `Either` にも許すと、次のようなことができるようになります（前述の `Foo|Bar` スタイルのシンタックスシュガーを使って書きます）。

```swift
class A {
    func foo() -> Int|String {
        return "abc"
    }
}

class B: A {
    // override して戻り値の型を Int に変更
    override func foo() -> Int {
        return 42
    }
}
```

ここまで来ると _Union Type_ にしか見えません。

### Either Chaining

`Optional` には _Optional Chaining_ という便利な構文があります。 Swift では `Optional` を使ってタイプセーフなコードが書ける代わりにすぐに `Optional` だらけになってしまうので、このような便利な構文は重宝します。

```swift
let foo: Foo? = ...
let baz: Baz? = foo?.bar?.baz // foo か bar か baz のどれかが　nil なら nil
```

`Either` でも同じことが言えます。次のように _Optional Chaining_ のような構文があれば便利です。

```swift
let foo: Error|Foo = ...
let baz: Error|Baz = foo?.bar?.baz // foo か bar か baz のどれかが　Error なら Error
```

### Forced Unwrapping

エラーを無視するために _Forced Unwrapping_ も欲しい所です。

```swift
let foo: Foo? = ...
let qux: Qux = foo!.qux // foo が nil でないことを確信、 nil ならクラッシュ
```

```swift
let foo: Error|Foo = ...
let qux: Qux = foo!.qux // foo が nil でないことを確信、 nil ならクラッシュ
```

### Either Binding

_Optional Binding_ も `Optional` だけに許されている便利構文です。

```swift
let fooOrNil: Foo? = ...
if let foo = fooOrNil {
    // foo を使った処理
    ...
}
```

これも `Either` でできれば便利です。

```swift
let fooOrError: Error|Foo = ...
if let foo = fooOrError {
    // foo を使った処理
    ...
}
```

### ?? 演算子

`Optional` には `??` という便利な演算子があります。

```swift
let fooOrNil: Foo? = ...
let foo: Foo = fooOrNil ?? Foo() // nil のときは Foo()
```

`Either` だと次のようになります。

```swift
let fooOrError: Error|Foo = ...
let foo: Foo = fooOrNil ?? Foo() // Error のときは Foo()
```

なお、 `??` はただの演算子なので自分で実装することもできます。そのため、　[gfx/Swift-SwiftEither](https://github.com/gfx/Swift-SwiftEither) や [antitypical/Result](https://github.com/antitypical/Result) では実装されています。

### init|

Swift の _イニシャライザ_ は、インスタンスの構築に失敗したときに `nil` を返せるように _Failable Initilizer_ という仕組みがあります。次の `init?` は `Int` の　_イニシャライザ_ ですが、その戻り値の型は `Int` ではなく `Int?` です。

```swift
struct Int {
    // Int としてのパースに失敗したら nil を return する
    init?(_ text:String) {
        ...
    }
}
```

_イニシャライザ_ の失敗を考えるなら、当然エラー情報を返したいこともあるでしょう。現状では _イニシャライザ_ の戻り値の型はその型そのものか `Optional` だけですが、 `Either` も返す手段ができればうれしいです。そのときには　`init?` と一貫性があるように `init|` というキーワードを使うのがいいんじゃないでしょうか。

```swift
init|(foo: Foo, bar: Bar) {
    // 失敗した場合はエラー情報を Either に渡して return する
    ...
}
```

ただ、 `Either` のエラーの型を推論させるのでなければ、何かしらの方法で指定する方法が必要になります。

### try| 演算子

`try?` 演算子を使えば、 _do-try-catch_ を使わなくても簡単に `throws` 付の関数を扱うことができます。これは、 `ErrorType` の詳細はどうでも良くて、ただ失敗したことを知りたいだけの場合には重宝します。

例えば、前述の

```swift
func toScore(string: String) throws -> Int
```

の場合には

```swift
do {
    let score = try toScore("42")

    // score を使った処理
    ...
} catch {
    // エラー処理
    ...
}
```

となるところを、

```swift
if let score = try? toScore("42") {
    // score を使った処理
    ...
} else {
    // エラー処理
    ...
}
```

というように書けます。これだけだと大した違いが内容に思えますが、

```swift
let scoreOrNil: Int? = try? toScore("42")
```

として、その場でエラー処理をせずに値を取り回したり、式の途中で使って _Optional Chaining_ するなどできます。

同じことは `Either` にも言えます。そもそも Groff さんが述べているような `either` 関数が欲しいのは、 "Eitherとdo-try-catchの使い分け" でも述べたように _do-try-catch_ ではなく `Either` としてエラー処理がしたいからです。 `Either` であれば、値として取り回せる利便性を享受しながら、 `Optional` のようにエラー情報を捨ててしまうこともなく理想的です。

`either` 関数でもいいのですが、せっかくだったら `try?` 演算子と一貫性を持たせて `try|` 演算子とするのが望ましいと思います。

```swift
let scoreOrError: ScoreFormatError|Int = try| toScore("42")
```

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

Swift に `Either` が追加されそうなので、それがどのようなものになるか、どのようなものであれば望ましいかを考えてみました。

Swift の `Optional` が強力なのは、タイプセーフであることに加えて、その反面の面倒さを軽減するための様々な言語サポートが提供されているからです。 `Either` にも同様の言語サポートを提供することで使い勝手の良いものとなるでしょう。そして、それらは自然で（ `Foo|Bar` など）、これまでのものと一貫性のあるもの（ `init|` や `try|` など）であってほしいです。

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

[^1]: Joe Groff: https://twitter.com/jckarter/status/608002431578865664
[^2]: ちなみに、このツイートを見つけたきっかけは [Argo の issue](https://github.com/thoughtbot/Argo/issues/150) を眺めていたことです。
[^3]: 本当は `@noescape` があった方がいいですが、本題とは関係ないので省略します。あと、 `map` の実装で `.Right(transform($0))` となっている部分を本当は `Either(transform($0))` としたかったのですが、コンパイラがクラッシュしてしまったので諦めました。
[^4]: これと同種の話として、 Swift の　`Optional` は `Int??` で `Optional<Optional<Int>>` という二重の `Optional` を表せますが、 [Kotlin](http://kotlinlang.org/) の [_Nullable Type_](http://kotlinlang.org/docs/reference/null-safety.html) では `Int??` は `Int?` と同じになってしまうという話があります。