Proposalには載っていないSwift 5のasync/awaitが素晴らしいと思う理論的背景

##### 追記 (2020-08-05)

投稿時には `async/await` が Swift 5 で導入されそうでしたが、 2020 年 8 月（ Swift 5.2 ）現在ではまだ `async/await` は導入されておらず、 Swift 6 での導入が有力になっています。

- `async/await` は "[Swift Concurrency Manifesto](https://gist.github.com/lattner/31ed37682ef1576b16bca1432ea9f782)" の最初の Part に挙げられていますが、公式にアナウンスされた "[On the road to Swift 6](https://forums.swift.org/t/on-the-road-to-swift-6/32862)" の中で Concurrency が挙げられています。
- 先日、 `async` に関する [PR](https://github.com/apple/swift/pull/33147) が Swift リポジトリの master ブランチにマージされました。

---

2ヶ月ほど前、 Chris Lattner から swift-evolution に ["async/await + actors"](https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170814/038892.html) というタイトルで驚きのメールが流れました。

<img width="1087" alt="async-await-actors.png" src="https://qiita-image-store.s3.amazonaws.com/0/47085/c33a0a36-30d2-42d6-eb78-c1da6ede27b2.png">

これは Swift における並行処理関連の提案で、主に `async/await` と `actor` についてのものです。本投稿では、そのうち `async/await` に着目します。 `async/await` といえば C# や JavaScript が思い浮かびますが、 Swift の `async/await` は Swift にフィットするように独自の変更が加えられています。

<blockquote class="twitter-tweet" data-lang="en"><p lang="en" dir="ltr">understanding async/await in 7 seconds <a href="https://t.co/IJOQJ2DR35">pic.twitter.com/IJOQJ2DR35</a></p>&mdash; Wassim Chegham シ (@manekinekko) <a href="https://twitter.com/manekinekko/status/855824609299636230?ref_src=twsrc%5Etfw">April 22, 2017</a></blockquote>

（ JavaScript の `Promise` と `async/await` ）

まだ正式な Proposal になっていませんが、[こちら](https://gist.github.com/lattner/429b9070918248274f25b714dcfc7619) から Proposal 全文を閲覧できます。これを読めば Swift の `async/await` がどのようなもので、何のために提案されているのかがわかります。この Proposal は平易な英語で書かれていて読みやすいので、是非一読をオススメします。 Proposal に書かれていることをそのまま書いてもおもしろくないので、 **この投稿では Proposal では詳しく述べられていない背景思想について説明します**。とはいえ、予備知識がなくても、基本的な Swift の構文さえ知っていれば `async/await` について一通り理解できるように説明するので安心して下さい。

実は、僕はこの Proposal の `async/await` とほぼ同じ内容のものを提案しようと考えていました。 GW 頃にまとめ、 [Ray Fix さん](https://twitter.com/rayfix)に[英文のネイティブチェック](https://gist.github.com/koher/3e04b4f1b8adbbf0379d38c0ad83a3ea/revisions#diff-74461ad55c78f93ada5df9d114aa66b4)をしてもらったものが[こちら](https://gist.github.com/koher/3e04b4f1b8adbbf0379d38c0ad83a3ea)です。ただ、当時すでに Swift 4 のまとめの時期に入っており新機能を提案できる感じではありませんでした。 Swift 5 の議論が始まったら投稿しようと思ってそのまま寝かしていました。そして、 8 月にようやく Swift 5 の議論が始まったのでそろそろ投稿しようかと思ってたところに冒頭の [Chris Lattner](https://twitter.com/clattner_llvm?lang=en) のメールが投稿されました。中身を確認してみると自分が考えていたのとほぼ同じ内容だったのでびっくりというわけです。

<img width="1537" alt="native-check.png" src="https://qiita-image-store.s3.amazonaws.com/0/47085/bc19a961-c9c7-50b8-4300-d501e1f24f82.png">

（原型をとどめないネイティブチェックの図）

しかし、 Proposal の説明は自体はとてもわかりやすいのですが、その説明は僕がほぼ同じ `async/await` に思い至った経緯とはずいぶん異なっていました。この投稿では、僕がそのような `async/await` に至った過程を説明することで、なぜこの `async/await` が Swift に良くフィットするのかを説明します。

## コールバック地獄

Swift の非同期処理にはコールバックが用いられることが多いです。 `Delegate` もありますが、 Obj-C 由来なのでここでは触れません。

コールバックの問題としてよく知られるものに **コールバック地獄** があります。↓のように、複数の非同期処理を連ねるとピラミッド状のネストが生まれてしまいます。可読性もメンテナンス性も良くありません。

```swift
func downloadFooImage(callback: @escaping (Image) -> ()) {
  downloadServerURL() { url in
    downloadJSON(from: url) { json in
      download(from: json["foo"]["image"]["url"].string! ) { imageData in
        callback(Image(data: imageData)!)
      }
    }
  }
}
```

## `Promise`

コールバック地獄の対策の一つとして、 JavaScript で有名になった `Promise` があります。

`Promise<Foo>` は今はまだ手に入っていないけど、将来のいつか手に入る `Foo` 型の値を意味します。たとえば、 `url` を渡して `Data` をダウンロードする関数 `download` を考えてみます。コールバック版と `Promise` 版のシグネチャはそれぞれ次のようになります。

```swift
// コールバック
func download(from url: URL, completion: @escaping (Data) -> ()) { ... }

// Promise
func download(from url: URL) -> Promise<Data> { ... }
```

`Promise<Data>` を将来のいつか手に入る `Data` 型の値と読めれば、 `url` を渡して `Promise<Data>` を返してくれる後者の方が（少なくとも僕は）わかりやすいと思います。

では、 `Promise` を使ってどのようにコールバック地獄を解消するのでしょうか？そのためにはもう少し `Promise` について説明しなければなりません。

### PromiseK

僕の勤務先である Qoncept では、 Swift 1.0 のリリースと同時に Swift を使い始めたんですが、 2014 年の年末頃にはコールバック地獄の問題が顕在化していました。そんなときに、僕の同僚の @omochimetaru が「 Swift にも JavaScript の `Promise` がほしい。」と言って Swift で再現したものをサクッと実装し、使い始めました。

僕はそのとき初めて `Promise` を知ったんですが、使ってみてなかなかいいなと思いました。しかし、使っている内に僕はいくつかの不満を抱き始めました。

たとえば、 Swift 1.0 の頃には `Optional` の `nil` でエラーを表すことが一般的でした。しかし、 JavaScript の `Promise` は非同期だけでなくエラーも扱っていました。非同期処理はエラー処理を伴うことが多いとはいえ、本質的には二つは直交した概念です。 Swift にはせっかく `Optional` があるのに、 `Promise` を使うときは `Promise` でエラー処理をするというのが気に入りませんでした。

そこで、 JavaScript の `Promise` からエラー処理に関する機能を取り除いて非同期処理に特化した `Promise` ライブラリ [PromiseK](https://github.com/koher/PromiseK) を作りました。 PromiseK の `Promise` は純粋に非同期であることだけを表します。エラーが起こり得ることは `Promise<Optional<Foo>>` のように `Optional` 等と組み合わせて表現します。

提案されている `async/await` と、このエラー処理を取り除いた `Promise` は強く関連しているので、 PromiseK をベースに `Promise` について説明します。

### 結果のハンドリング

コールバックだろうが `Promise` だろうが、非同期処理の結果を受け取ってハンドリングすることは必須です。先程の `download` 関数を利用するコードはそれぞれ次のようになります。

```swift
// コールバック
download(from: url) { (data: Data) in // 非同期処理完了時に実行
  // `data` を使う処理
}

// Promise
let data: Promise<Data> = download(from: url)
data.get { (data: Data) in // 非同期処理完了時に実行
  // `data` を使う処理
}
```

このコードを見ただけでは、 `Promise` を使って何がうれしいのかわからないと思います。重要なのは、 `Promise` 版の場合は結果が値として返されるということです。 `Promise<Data>` という形で非同期処理そのものが値として返されるので、それを取り回して複数の非同期処理を結合して順番に実行したり、並列に走らせてから最後に結合したりという操作が可能になります。

具体的には後で詳しく説明しますが、そのように複数の非同期処理に対して結合などの操作を実行できることがコールバック地獄のネストを取り除くことを可能にします。なので、先程のコードのように単発で非同期処理の結果を受け取るだけでは `Promise` のうまみがわかりませんが、値として取り回せるということが重要なポイントです。

### `map`

では、どのように非同期処理を操作するのでしょう？ JavaScript の `Promise` では `then` メソッド https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then が肝となります。しかし、　**僕が JavaScript の `Promise` について気に入らなかったもう一つの点がその `then` メソッドでした**。

当時モナドについて知りたいと思って ["すごいHaskell"](https://www.amazon.co.jp/dp/B009RO80XY) を読んでいた僕は、 `Promise` はモナドで `then` メソッドは `map` と `flatMap` をごちゃ混ぜにしたものだと気付きました。モナドというのは、　`Array` や `Optional` のように `map` と `flatMap` を持っている型のことです。そこで、僕は PromiseK を実装するに当たって `then` メソッドを廃止し、 `map` メソッドと `flatMap` メソッドに分解することにしました。

`map` メソッドは Swift を書いていると馴染み深いんじゃないかと思います。たとえば、 `Array<Int>` ( `[Int]` )の各要素を 2 乗するコードは次のように書けます。

```swift
let numbers: Array<Int> = [2, 3, 5]
let squares: Array<Int> = numbers.map { $0 * $0 } // [4, 9, 25]
```

`Optional` でも同じです。 `map` メソッドを使って、値がある場合は 2 乗し、 `nil` の場合は `nil` のままとすることができます。

```swift
let number: Optional<Int> = 3
let square: Optional<Int> = number.map { $0 * $0 } // Optional(9)
```

`Optional` は値が入っているかもしれないし、入っていないかもしれない箱だと考えられます。 `Optional<Int>` ( `Int?` ) なら `Int` が入っているかもしれないし、入っていない（ `nil` ）かもしれないわけです。

`Promise` も同じように箱だと考えられます。 `Promise` はどんな箱かというと、今はまだ手に入っていないけれども将来値が手に入る箱です。それなら、同じように `map` を使って将来手に入る値を 2 乗することができてもおかしくありません。

`Promise` を使って将来手に入る値を 2 乗するコードは次のようになります。 `Array` や `Optional` とまったく同じなのがわかると思います。

```swift
let number: Promise<Int> = downloadInt(from: url)
let square: Promise<Int> = number.map { $0 * $0 }
```

この場合、 `number` に `get` して将来得られる値が `3` だとすると、 `square` に `get` して将来得られる値は `9` となります。

このようにして、 `Promise` の `map` メソッドを使えば **今はまだ手に入っていない将来の値に対して操作を加えることができます**。

### `flatMap`

`Promise` にとってより重要なのが `flatMap` です。

`Promise` の `flatMap` を考える前に、まず `Optional` の `flatMap` [(API Reference)](https://developer.apple.com/documentation/swift/optional/1540500-flatmap) についておさらいしましょう。

たとえば、 `[String: String]` から値を取り出し、得られた `String` を整数に変換したいとします。 Web アプリで GET パラメータを処理する場合などにありがちです。この場合、 `parameters["id"]` 等で得られる値は `String` ではなく `String?` です。また、 `String` を `Int` に変換する処理も、パースに失敗すると `nil` となるので `Int?` が返されます。

これを単純に結合すると `Optional` がネストして `Optional<Optional<Int>` ( `Int??` ) になってしまします。

```swift
let idString: Optional<String> = parameters["id"]
let id = idString.map { Int($0) } // `id` の型は `Optional<Optional<Int>>`
```

今求めているのは、 `parameters["id"]` か `Int($0)` のどちらかに失敗すると `nil` になり、両方に成功した場合には `Int` の `id` が得られることです。つまり、結果としてほしい値の型は `Optional<Int>` です。しかし、先程のコードでは `Optional<Optional<Int>>` のようにネストしてしまいました。そんなときに役に立つのが `flatMap` です。

`map` の代わりに `flatMap` を使うと、ネストした `Optional` をつぶしてフラット（一重）にしてくれます。

```swift
let idString: Optional<String> = parameters["id"]
let id: Optional<Int> = idString.flatMap { Int($0) }

```

これは `parameters["id"]` と `Int($0)` という二つの失敗し得る処理を結合したとも考えられます。失敗しうる処理が結合されると、どちらか一方でも失敗したら `nil` になり、両方に成功した場合だけ結果が得られるわけです。

同じことが `Promise` でも言えます。まずダウンロード先の `URL` をダウンロードし、それを使って `id` をダウンロードする二つの非同期処理を次のように `flatMap` で結合できます。

```swift
let idURL: Promise<URL> = downloadURL(from: url)
let id: Promise<Int> = idURL.flatMap { downloadInt(from: $0) }
```

`Optional` を `flatMap` で結合すると両方に成功した場合だけ値が得られました。 `Promise` では両方の非同期処理を順番に実行し、両方とも完了したときに初めて値が得られる `Promise` が得られます。

次のようにして `flatMap` を使うことで非同期処理を結合することができます。

```swift
let idURL: Promise<URL> = downloadURL(from: url)
let id: Promise<Int> = idURL.flatMap { downloadInt(from: $0) }

id.get { (id: Int) in
  // `downloadURL` がまず実行され、次に `downloadInt` が実行され、
  // 両方の非同期処理が完了したときに初めてこのクロージャが実行される。
}
```

では、これを使って先程のコールバック地獄を解消してみましょう。先程挙げた↓のコールバック地獄ですが、

```swift
func downloadFooImage(callback: @escaping (Image) -> ()) {
  downloadServerURL() { url in
    downloadJSON(from: url) { json in
      download(from: json["foo"]["image"]["url"].string! ) { imageData in
        callback(Image(data: imageData)!)
      }
    }
  }
}
```

コールバックの部分がすべて `Promise` なら↓のように `flatMap` の連結で書けます。

```swift
func downloadFooImage() -> Promise<Image> {
  return downloadServerURL().flatMap { url in
    downloadJSON(from: url)
  }.flatMap { json in
    download(from: json["foo"]["image"]["url"].string! )
  }.map { imageData in
    Image(data: imageData)!
  }
}
```

これがわかりやすいかどうかは人によると思います。ネストが深くてもコールバックの方が読みやすいという人も当然いると思います。

それでは、なぜこんなにも延々と `Promise` と `flatMap` の話をしているのかと言うと、 `async` は `Promise` を `return` することに、 `await` は `flatMap` に対応するからです。

`Promise` を知っていると `async/await` がどういうものなのか格段に理解しやすくなります。

### コールバックの `Promise` 化

さて、ここまでの話は `Promise` のレベル 1 で、ここからがレベル 2 です。これまでは `Promise` 化された API をどのように使うかについてで、ここからは自分で `Promise` 化された API を作る話です。

ちなみに、レベル 3 は自分で `Promise` を作る話です。今日のテーマには含まれませんが、すごく勉強になるので `Promise` を実装してみることをオススメします。

`Promise` がおもしろいのは、並行処理の仕組みそのものとは独立していることです。 iOS アプリ開発であれば、 GCD や Foundation の `Thread` など様々な方法で並行処理を実現できます。 `Promise` はそれらと組み合わせて利用することができます。また、コールバックで実装された既存のメソッド（ `UIView.animate(...)` 等）を `Promise` 化することもできます。

たとえば、 `func foo(_ completion: (Int) -> ())` というコールバックで結果を受け取る関数があったとして、これを `Promise` 化したものは次のように実装できます。

```swift
func promisedFoo() -> Promise<Int> {
  return Promise<Int> { fulfill in
    foo { fulfill($0) }
  }
}
```

ちょっと複雑ですが何をしているのが順に見ていきましょう。まず、 `Promise` のイニシャライザのシグネチャは次のようになっています。

```swift
init(_ executor: (_ fulfill: @escaping (Value) -> ()) -> ())
```

`Promise` は生まれた直後には値を持っていませんが、いつかは非同期処理が終わって値を手に入れなければなりません。 `Promise` に値を通知する手段を提供するのが `fulfill` です。　`Promise<Foo>` のとき、 `fulfill` は `(Foo) -> ()` という型の関数です。 `fulfill` の引数に `Foo` 型を与えて呼び出せば `Promise` の非同期処理は完了し `Foo` が得られたことを意味します。

極端な話、↓のようにすれば即時に値が手に入る `Promise` を作ることもできます。

```swift
Promise<Int> { fulfill in
  fulfill(42)
}
```

先の例では、このクロージャ式の中で非同期処理 `foo` を呼び出し、コールバックの中で `fulfill` を呼び出すことでコールバックを `Promise` 化しているわけです。

```swift
Promise<Int> { fulfill in
  foo { fulfill($0) }
}
```

この仕組みを使えば、任意の非同期処理を `Promise` 化することが可能です。後でもう一度触れますが、この `Promise` のイニシャライザは `async/await` の Proposal 中の `suspendAsync` に相当します。

また、 `async/await` の話と直接関係ないですが、僕が `Promise` についておもしろいと思うのは、それそのものが状態でできているような存在なのに、イミュータブルのように振る舞う点です。 `Promise` を使う側はすでに非同期処理が終わって値が決定されているのかを気にする必要はないですし、一度決定された値が後で変更されることもありません。何度 `get` しても同じ値が得られます。 `get` や `map`, `flatMap` に渡した関数がいつ呼ばれるかがわからないだけで、得られる値は常に一つです。状態変化を扱うのにそれを内部に隠蔽し、利用者はイミュータブルなコードを書けるというのが `Promise` のおもしろいところです。

さらに余談ですが、この `Promise` の実装は[ここ](https://github.com/koher/PromiseK/blob/dev-3.0/Sources/PromiseK/Promise.swift) にあります。実質的にはわずか 38 行のコードです。これは、僕がこれまでに Swift で書いた最もキレイなコードの一つだと思うので、良かったら見てみて下さい。

## `throws/try`

さて、 Swift 1 から少し時代が進んで、 2015 年の夏に Swift 2.0 がリリースされました。 Swift 2.0 で最も注目すべきだったのは何と言っても `throws/try` です。なぜここで突然 `throws/try` の話を始めたかと言うと、 `throws/try` が `async/await` ととても良く似た仕組みの上に成り立っているからです。

Swift 1 時代には `Optional` を返すことで失敗し得る処理を扱うことができました。しかし、 `nil` ではエラーの理由を表すことができないので、色々な理由でエラーが起こり得る場合には不便です。特に、エラーの原因によって処理を分けることは `Optional` では不可能です。また、 Obj-C 由来の `NSError` の扱いも Swift 1 時代は大変でした。

Swift 2.0 からは、 `throws/try` を使うことによってエレガントにエラー処理をすることができるようになりました。

Swift の `throws/try` は Java の検査例外とよく似ているのですが、そのまま持ってきたのではなく Swift にフィットするようによく考えて変更されています。 "SwiftはどのようにJavaの検査例外を改善したか" については[こちらの投稿](https://qiita.com/koher/items/e4c1d88981291c35d571)にまとめてあります。この投稿はあまり伸びませんでしたが、個人的にはとてもおもしろいことが書いてあると思うのでよかったら読んでみて下さい。

`throws/try` を使えば失敗し得る処理を次のように書けます。

```swift
func loadFoo() throws -> Foo { ... }

do {
  let foo: Foo = try loadFoo()
  // `foo` を使う処理
} catch error {
  // エラー処理
}
```

この `throws/try` の仕組自体は僕はとても素晴らしいと感じていますが、一つ大きな問題があります。それが、非同期処理と組み合わせて使いづらいことです。

たとえば、これまで `download` 関数が失敗する可能性を無視してきましたが、現実的にはダウンロードは失敗し得る処理です。しかし、 `download` に `throws` を付けることはできません。

```swift
// コールバック（これではダメ⛔）
func download(from url: URL, completion: @escaping (Data) -> ()) throws { ... }

// Promise （これもダメ⛔）
func download(from url: URL) throws -> Promise<Data> { ... }
```

なぜなら、 `throws` によるエラーは関数のコールに対して同期的に対処しなければならないからです。しかし、ダウンロード中のエラーは非同期に発生するので、同期的に処理することはできません。

```swift
do {
  download(from: url) { (data: Data) in
    // 本当はここでエラー処理したい
  }
} catch let error {
  // ここでエラー処理したいわけではない
}
```

↓のようにすれば無理やりコールバックや `Promise` でエラー処理させることができますがちょっと辛いです。

```swift
// コールバック（一応できるがわかりづらい🤔）
func download(from url: URL, completion: @escaping (() throws -> Data) -> ()) throws { ... }

// Promise （これもできるがわかりづらい🤔）
func download(from url: URL) throws -> Promise<() throws -> Data> { ... }
```

これを使うコードは↓です。クロージャで受け取るのが値（ `data` ）ではなく関数（ `getData` ）という点がわかりづらいです。

```swift
download(from: url) { getData in
  do {
    let data = try getData()
    // `data` を使う処理
  } catch let error {
    // エラー処理
  }
}

```

## `Result`

`throws/try` は非同期処理と相性が悪いということで `Result` ライブラリが流行りました。一番有名なのは [antitypical/Result](https://github.com/antitypical/Result) です。しかし、ここでは話の都合上、僕が実装した [ResultK](https://github.com/koher/ResultK) を使って説明します。

antitypical/Result と ResultK の一番の違いは、前者が `Result<T, E: Error>` と型パラメータでエラーの型を指定できるのに対して、後者は `Result<T>` とエラーの型が指定できないことです。 Swift の `throws` 節には Java のようにエラーの型を指定することができません。そのため、エラーの型が指定できない `Result` の方が `throws/try` にキレイに対応します。それが ResultK で説明する理由です。

`Result` は次のように宣言されています。成功して `T` 型の値を持つか、失敗して `Error` を持つかのどちらかであることを表す型です。

```swift
enum Result<T> {
    case success(T)
    case failure(Error)
}
```

`Result` を使えば `throws` で書かれた関数を↓のように書き換えることができます。 `throws` を付与するのと `Result` を `return` するのが対応していることに注目して下さい。

```swift
// throws/try
func loadFoo() throws -> Foo { ... }

// Result
func loadFoo() -> Result<Foo> { ... }
```

`Result` は `enum` なので、↓のようにしてエラー処理することができます。

```swift
switch (loadFoo()) {
case .success(let foo)
  // `foo` を使う処理
case .failure(let error)
  // エラー処理
}
```

`Result` を使ってうれしいのは非同期処理と組み合わせたときです。 `Result` があれば先程の `download` は次のように書けます。

```swift
// コールバック（非同期処理の結果が `Result<Data>` で得られるのでわかりやすい✅）
func download(from url: URL, completion: @escaping (Result<Data>) -> ()) { ... }

// Promise （非同期処理の結果が `Result<Data>` で得られるのでわかりやすい✅）
func download(from url: URL) -> Promise<Result<Data>> { ... }
```

### `map`, `flatMap`

`Result` もモナドなので、 `Optional` や `Promise` と同じく `map` や `flatMap` を持ちます。

たとえば、 `map` を使って `Result` の中身を 2 乗するコードは↓のようになります。　`Optional` や `Promise` のときとまったく同じですね。

```swift
let number: Result<Int> = loadInt(from: path)
let square: Result<Int> = number.map { $0 * $0 }
```

`flatMap` も同様です。 `Optional` のときと同じように、 `flatMap` を使って失敗し得る処理を結合することができます。

```swift
let json: Result<Data> = loadData(from: path)
let user: Result<User> = json.flatMap { decodeUser(from: $0) }
```

この処理では、まず JSON ファイルからデータを読み込み、次の読み込まれたデータを `User` 型の値にデコードしています。どちらも失敗しうる処理であり、 `flatMap` で結合して両方に成功した場合だけ `User` が得られます。

### `throws/try` と `Result`

先程、関数に `throws` を付与するのと `Result` を `return` するのは同じだと言いました。

`flatMap` にも対応するものがあります。 `throws/try` と `Result` で同じ処理が書かれた次のコードを見比べてみて下さい。

```swift
// throws/try
let json: Data = try loadData(from: path)
let user: User = try decodeUser(from: json)
// `user` を使う処理

// Result
loadData(from: path).flatMap { (json: Data) in
  decodeUser(from: json)
}.flatMap { (user: User) in
  // `user` を使う処理
}
```

どちらのコードも `loadData` と `decodeUser` に成功した場合だけ `user` が得られ、失敗した場合にはその `Error` が得られます。一番重要なのは、 `flatMap` でモナドの中身を取り出して処理しているのと同じように、 `try` もエラーの場合を剥がして中身を取り出す処理になっていることです。 **`try` して代入するのは本質的に `flatMap` と同じことなのです。**

### 小まとめ

- `throws` を付与 == `Result` を `return`
- `try` して代入 == `flatMap`

```swift
// throws/try
func loadUser(from path: String) throws -> User {
  let json: Data = try loadData(from: path)
  return try decodeUser(from: json)
}

// Result
func loadUser(from path: String) -> Result<User> {
  return loadData(from: path).flatMap { (json: Data) in
    decodeUser(from: json)
  }
}
```

## `Result` : `throws/try` = `Promise` : ?

さらに時は進んで 2016 年の 1 月、僕は `Result` やエラー処理をテーマに [try! Swift](https://www.tryswift.co/) の発表の準備をしていました。

`Result` は `throws/try` と違って非同期処理と一緒に使いやすいです。一方で `flatMap` をチェーンするコードより `try` して代入を繰り返すコードの方がわかりやすいです。両者のいいとこどりができたら最高です。なので、 `throws -> Foo` を `Result<Foo>` を `return` することのシンタックスシュガーにして、二つの世界を自由に行き来できるようにすればいいんじゃないかと考えました。

たとえば、↓のような感じです。これなら、普段は `throws/try` で使っておいて、非同期処理などで必要なときだけ `Result` として扱えます。

```swift
func loadFoo() throws -> Foo { // `-> Result<Foo>` でも同じ
  ...
}

let foo1: Foo = try loadFoo()     // `try` すると `Foo` が得られる
let foo2: Result<Foo> = loadFoo() // `try` しないと `Result<Foo>` が得られる
```

このような話を発表しようと考えているときに、ふと `Result` に対して `throws/try` が考えられるなら、 `Promise` に対しても同じようなものが考えられないかと思いました。なにせ、 `Result` も `Promise` も同じモナドです。 `try` して代入することが `flatMap` に相当するなら、同じことが `Promise` に大してもできるはずです。

そう考えると、 C# の `async/await` が（少し変更は必要ですが）ぴたりとそれに当てはまることに気付きました。 C# の `async` は次のように `async` を付けた上で `Promise` （ C# では `Task` ）を返します。

```swift
// C# の `async` を Swift っぽい構文で書くと
func download(from url: URL) async -> Promise<Data> { ... }
```

`async` を書いた上で `Promise` を返すのは冗長なので、↓のような構文にすると `Promise` : `async` = `Result` : `throws` でぴたりとハマります。

```swift
// Swift にフィットするように構文を変更
func download(from url: URL) async -> Data { ... }
```

つまり、↓の二つを同じ意味にしてしまうわけです。 `throws` と `Result` の関係とまったく同じです。

```swift
// async
func download(from url: URL) async -> Data { ... }

// Promise
func download(from url: URL) -> Promise<Data> { ... }
```

`throws` と `async` が対応するなら `try` に対応するものも必要です。これも `await` と考えればぴったりです。 `throws/try` と `Result` のときとまったく同じです。

```swift
// async/await
let data: Data = await download(from: url)
// `data` を使う処理

// Promise
download(from: url).flatMap { (data: Data) in
  // `data` を使う処理
}
```

**このような `async/await` を考えると `throws` : `try` : `Result` = `async` : `await` : `Promise` という関係が成り立ちます。なんて美しい関係でしょう。**

## 非同期エラー処理

`Promise` と `Result` が組み合わせられるように、 `throws/try` と `async/await` も組み合わせられます。非同期かつ失敗し得る `download` 関数は次のように書けます。

```swift
// async/await + throws/try
func download(from url: URL) async throws -> Data { ... }

// Promise + Result
func download(from url: URL) -> Promise<Result<Data>> { ... }
```

これらを使うときのコードは↓です。一つ目の `flatMap` が `await` に、二つ目の `flatMap` が `try` に対応しています。

```swift
// async/await + throws/try
let data: Data = try await download(from: url)
// `data` を使う処理

// Promise + Result
download(from: url).flatMap { $0.flatMap { (data: Data) in
  // `data` を使う処理
} }
```

## モナド地獄

そんなわけで僕は `throws` は `Result` を、 `async` は `Promise` を返すことのシュガーにしたらいいんじゃないかということを [try! Swift で話しました](https://academy.realm.io/posts/tryswift-yuta-koshizawa-error-handling-swift/)。このときに Ray Fix さんに興味を持っていただき「もし Proposal を出すなら英文チェックするよ。」と申し出て下さったことから、冒頭に書いたネイティブチェックにつながりました。

try! Swift が終わって、 `throws` を `Result` のシュガーにする部分だけを切り出して [swift-evolution](https://github.com/apple/swift-evolution) に投げたところ、 Core Team の Joe Groff から[こちらのコメント](https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160314/012545.html)をもらいました。以下、僕の解釈で説明します。

たとえば、 `Array<Data>` があったとして、これをすべてデコードして `Array<User>` に変更したいとします。

```swift
let jsons: Array<Data> = ...
let users: Array<Result<Data>> = jsons.map { decodeUser(from: $0) }
```

しかし、得られたのは `Array<Result<User>>` です。一つでも失敗したらエラーとしたい場合ほしいのは `Result<Array<User>>` です。　Haskell などの言語では、 `Array<Result<User>>` を `Result<Array<User>>` に変換するための `sequence` という関数が用意されていたりします。この他にも `Result<Promise<Result<T>>` → `Promise<Result<T>>` 、 `Array<Result<Promise<T>>` → `Promise<Result<Array<T>>` なんかもやりたくなりそうです。

極端な話、次のようなことをやろうとしたら、モナド的には戻り値の型は `Result<Promise<Result<Promise<Result<Foo>>>>>` です。

```swift
let a = try ...
let b = await ...
let c = try ...
let d = await ...
let e = try ...
return Foo(a, b, c, d, e)
```

でも、 99% のケースでは本当にほしいのは `Promise<Result<Foo>>` のはずです。このモナドパズルを解かないといけないのは **モナド地獄** です。

`async/await` と `throws/try` であれば `async throws -> Foo` とすれば良いだけです。入れ子のパズルに苦しめられることもありません。これの意味するところは、 **`throws/try` や `async/await` はモナドパズルの解き方を定めていて、それが自動で適用される** ということです。

この話に関連して面白いのが `rethrows` です。 `map` して `Result` を返した場合は結果は `Array<Result<User>>` となりますが、エラーを `throw` すると `map` 自体がエラーを `throw` します。言い換えると、 `Result<Array<User>>` 相当のところまで変換してくれているということです。

```swift
// throws/try
let users: Array<User> = try jsons.map { try decode(from: $0) } // `Result<Array<User>>` 相当

// Result
let users: Array<Resut<User>> = jsons.map { decode(from: $0) }
```

`Array<Result<T>>` がほしいことは滅多にないので、 `rethrows` が勝手にモナドのネスト順序を入れ替えて `Result<Array<T>>` 相当まで変換してくれているということです。

## `Promise` のない `async/await`

Swift が `Result` を採用しない道を進むなら、 `async/await` にも `Promise` がない方が良いように思います。

C# や JavaScript の `async/await` は `Promise` （ C# では `Task` ）の上に構築されているので、 `Promise` のない `async/await` は挑戦的です。しかし、 `throws/try` が `Result` なしで実現できているのだから `async/await` にもできそうなものです。

そんなことを [SwiftJP Slack などで話してた](https://gist.github.com/koher/5cd16adac7a62b6d3eb0b910ccc13534) んですが、 swift-evolution で非同期処理の話が始まらないので提案せずに放置していました。しかし、今年の GW 頃にやっぱり Swift に `async/await` を導入するならこれしかない！と思い立ってまとめたのが冒頭で挙げた[こちら](https://gist.github.com/koher/3e04b4f1b8adbbf0379d38c0ad83a3ea)です。

### `beginAsync` と `suspendAsync`

単に `Promise` を返す代わりに `async` と書き、 `flatMap` の代わりに `await` するのではいけません。 `async/await` から `Promise` を取り除くに当たっては、 `Promise` の `get` と `init` に相当するものも提供しなければなりません。それが `beginAsync` と `suspendAsync` です（僕の提案中では `nonblock` と `asyncronize` です。さすがに名称は異なってますが、同じ道具が必要になってるのがおもしろいです）。

`beginAsync` と `suspendAsync` のシグネチャは↓です。

```swift
func beginAsync(_ body: () async throws -> Void) rethrows -> Void

func suspendAsync<T>(
  _ body: (_ continuation: @escaping (T) -> ()) -> ()
) async -> T

func suspendAsync<T>(
  _ body: (_ continuation: @escaping (T) -> (),
           _ error: @escaping (Error) -> ()) -> ()
) async throws -> T
```

`Promise` では `get` を使って非同期的に値を受け取れました。 `beginAsync` を使えばこれと似たようなことができます。

```swift
// Promise
download(from: url).get { data in
  // `data` を使う処理
}

// async/await
beginAsync {
  let data = await download(from: url)
  // `data` を使う処理
}
```

また、 `Promise` のイニシャライザを使ってコールバックで値を受け取る API を `Promise` 化できました。これも `suspendAsync` で似たことができます。

```swift
// Promise
Promise<Data> { fulfill in
  download(from: url) { data in
    fulfill(data)
  }
}

// async/await
await suspendAsync { fulfill in
  await download(from: url) { data in}
    fulfill(data)
  }
}
```

こうして、 `Promise` がなくても `async/await` を実現することができました。

やや余談ですが、 Proposal の中では `beginAsync` の `body` に `throws` が付けられており、 `beginAsync` 自体も `rethrows` になっています。

```swift
func beginAsync(_ body: () async throws -> Void) rethrows -> Void
```

僕はこの `throws` と `rethrows` には反対です。 `beginAsync` に渡された `body` は非同期処理を行うので、即座にエラーを `throw` することができません。 `beginAsync` がエラーを `rethrow` できるのは、 `body` の中の最初の `await` までにエラーが `throw` された場合だけです。

```swift
do {
  try beginAsync {
    try foo() // ここで発生したエラーを・・・
    await bar()
  }
} catch { // ここで `catch`
  // エラー処理
}
```

非同期的に発生したエラーは `catch` できないので、エラーが `throw` されたらクラッシュするしかありません。

```swift
do {
  try beginAsync {
    await bar()
    try foo() // ここでエラーが発生しても・・・
  }
} catch { // ここで `catch` できないのでクラッシュ！
  // エラー処理
}
```

最初の `await` の前に `try` したい場合は、それを `beginAsync` の外に出せるはずです。

```swift
do {
  try foo() // `beginAsync` の外に出す
  beginAsync {
    await bar()
  }
} catch {
  // エラー処理
}
```

もし `beginAsync` の `body` に `throws` が付いてなければ、 `body` の中でエラー処理が強制されるので、 `await` してから `try` のようなケースも安全に対処できます。

```swift
beginAsync {
  do {
    await bar()
    try foo()
  } catch { // これがないとコンパイルエラー
    // エラー処理
  }
}
```

せっかくコンパイル時にチェック可能なエラー処理機構を持っているのに、 `beginAsync` に渡すクロージャの中ではそれが台無しになってしまいます。

この点については一度 swift-evolution に書いたのですがうまく伝わってなさそうなので、今度もう一度投稿したいと考えています。

### 小まとめ

長々と書いてきましたが、 Proposal の中には出てこない `Promise` モナドを考えて、 `Result` や `throws/try` との関係を考えると、 Swift にフィットする `async/await` はこれしかないという気持ちになります。

その根拠は関係が「美しい」ことだけかもしれませんが、僕は経験則的に美しさは重要であると考えています。 **関係や構造が美しく整理できるときは物事の本質を突いていることが多いです。**

逆にそれを外すと、後で思いもよらないところで問題が発生して困ったりします。

たとえば、今回の `async/await` の Proposal にも、非同期処理はほぼ確実にエラーを伴うんだから `async` と `await` だけ書けば `throws` と `try` も付いていることにしてはどうかという意見もあります。しかし、この一見筋が通ったように見える意見には問題があります。たとえば、後で紹介する Generator を `async/await` で実現しようとすると `throws/try` であってほしくありません。

人はすべてを見通せるわけではないので一見問題がなさそうに見えても何かを見逃している可能性があります。できるだけ「美しい」方を選択することで、将来的なトラブルの可能性を低減できるんじゃないでしょうか。

## `throws` : `try` : △ = `async` : `await` : □

`throws/try` と `async/await` の関係を考えると Proposal に書かれていないいくつかの興味深いことが見えてきます。

### `throws` : `try` : `catch` = `async` : `await` : ?

`throws/try` の `do/catch` に対応するものを `async/await` にも考えるとどうなるでしょうか。 `do/catch` しない場合、 `try` を含む関数は必ず `throws` でなければなりません。

```swift
// do/catch なし
func foo() throws -> Bar { // `throws` 必須
  return try bar()
}

// do/catch あり
func foo() -> Bar { // `throws` でなくて良い
  do {
    return try bar()
  } catch {
    // エラー処理
    return Bar(...)
  }
}
```

`async/await` でも同様に `await` を含む関数は `async` でなければなりません。では、 `do/xxx` を考えるとどのようなものである必要があるでしょう？

```swift
// do/xxx なし
func foo() async -> Bar { // `async` 必須
  return await bar()
}

// do/xxx あり
func foo() -> Bar { // `async` でなくて良い
  do {
    return await bar()
  } xxx
}
```

このような挙動を実現する `xxx` は何を意味するでしょうか？ `bar()` は非同期なのに `foo()` は（ `async` でないので）同期的に `return` された `Bar` を返せています。

これを実現するには、 `xxx` によって非同期処理が同期化されなければなりません。つまり、 `xxx` は `bar()` の非同期処理が終わって結果が得られるまで待つという意味になるはずです。

「待つ」なので `xxx` に `wait` という単語を当てれば↓のようになります（他にも、 `sync` とか `block` とかの方がいいかもしれませんが）。

```swift
// do/wait なし
func foo() async -> Bar { // `async` 必須 → 非同期
  return try bar()
}

// do/wait あり
func foo() -> Bar { // `async` でなくて良い → 同期
  do {
    return await bar()
  } wait // `bar()` が完了するまでここで待つ
}
```

### `throws` : `try` : `try!` = `async` : `await` : ?

次は `try!` に当たるものを考えてみましょう。

`throws` が `Result` を返すことに対応することを考えると、 `try!` は強制的に `Result` を unwrap するようなものです。 `Optional` の `!` に近い操作です。

```swift
// ! なし
func foo() throws -> Bar { // `throws` 必須
  return try bar()
}

// ! あり
func foo() -> Bar { // `throws` でなくて良い
  return try! bar()
}
```

では、 `Promise` を unwrap する操作とか何でしょうか。それはやはり値が手に入るまで待つことを意味するのではないでしょうか。

```swift
// ! なし
func foo() async -> Bar { // `async` 必須
  return await bar()
}

// ! あり
func foo() -> Bar { // `async` でなくて良い
  return await! bar() // `bar()` が完了するまでここで待つ
}
```

`try!` が失敗時にクラッシュするのと同じように、処理が完了してなかったらクラッシュと考えることもできるかもしれません。しかし、 `try!` がクラッシュするのは `Result` でいう `.failure` 由来の性質だと思うので、僕はクラッシュではなく同期的に待つ方が自然だと思います。

ただし、 `await!` という表記は適切だとは思いません。 Swift では `!` が Forced Unwrapping の他に、 `try!`, `as!` など一貫して「失敗しうる処理の失敗を無視する（失敗したらハンドリングせずクラッシュさせる）」という意味で使われているからです。あくまで、 `try!` 相当の強制的に `Promise` を unwrap するような処理を考えると同期になるんじゃないかという話です。

### `throws` : `try` : `rethrows` = `async` : `await` : ?

次は `rethrows` です。これについては [Proposal でも簡単に触れられています](https://gist.github.com/lattner/429b9070918248274f25b714dcfc7619#rethrows-could-be-generalized-to-support-potentially-async-operations)。

`rethrows` が付与されている高階関数は、渡されたクロージャが `throws` だった場合に自分自身も `throws` になります。

```swift
array.map { foo($0) }         // `map` は `throws` でない
try array.map { try bar($0) } // `map` も `throws` になる

```

同じように、渡されたクロージャが `async` だった場合に自身も `async` になる `reasync` のようなものも考えられます。

```swift
array.map { foo($0) }             // `map` は `async` でない
await array.map { await bar($0) } // `map` も `async` になる
```

## Generator

ここまで非同期と言い続けてきましたが、 `async/await` はコルーチンを実現するための仕組みであって非同期に限ったものではありません。

非同期に限らない例として、いくつかの言語にある Generator と呼ばれる仕組みを紹介します。たとえば、↓は Python の例です。

```python
# Python
def foo():
  yield 2
  yield 3
  yield 5

g = foo()
print(next(g))  # 2
print(next(g))  # 3
print(next(g))  # 5
```

この `Generator` は、専用の言語機能を持たなくても `async/await` で実現することができます。たとえば、 Swift に `async/await` があったとして、↓のような `Generator` 型を作ることができます。

```swift
let g = Generator { yield in
  await yield(2)
  await yield(3)
  await yield(5)
}

print(g.next()!) // 2
print(g.next()!) // 3
print(g.next()!) // 5
```

`Generator` の実装例は[ここ](https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170821/039150.html)にあります。

別々の言語機能として持つのではなく、 `async/await` だけで両方実現できるのは本質を表していて美しいように思います。

## まとめ

- `throws` : `try` : `Result` = `async` : `await` : `Promise`
- 美しいは正義