Swift 3.1 を先取り👀

【追記】
本記事 + α の内容を以下で丁寧にまとめました(一部本記事のみに記載されている内容もありますが)。

- [Swift 3.1のリリースプロセスおよびそれに含まれる変更内容の紹介（前編） - Build Insider](http://www.buildinsider.net/column/ono-masayuki/005)
- [Swift 3.1のリリースプロセスおよびそれに含まれる変更内容の紹介（後編） - Build Insider](http://www.buildinsider.net/column/ono-masayuki/006)

---

そろそろ、Swift 3.1 のことも気になってくる頃かなと思って、それについて書いてみます。

# Swift 3.1 で予定されている変更点(現時点)

現在実装済みの主な変更点は、[Swift 3.1 の CHANGELOG](https://github.com/apple/swift/blob/master/CHANGELOG.md#swift-31) に記載されています。

現時点では、以下の3点が記載されています。

- [SR-1446: Nested generics](https://bugs.swift.org/browse/SR-1446)
- [SR-1009: Add methods to an Array containing a specific type](https://bugs.swift.org/browse/SR-1009)
- [SE-0045: Add prefix(while:) and drop(while:) to the stdlib](https://github.com/apple/swift-evolution/blob/master/proposals/0045-scan-takewhile-dropwhile.md)

他にも細かいバグ修正など含むはずですが、Swift リポジトリの CHANGELOG にはそこまで細かい粒度で記載しないポリシーのように見えます。

例えば、Swift 3.0.1 の細かい改善についても、CHANGELOG には記載されず、Xcode 8.1 のリリースノートへの記載のみとなっていました。

- [[Swift] Swift 3.0.1 の変更点 ｜ Developers.IO](http://dev.classmethod.jp/smartphone/iphone/swift-3-0-1/)
- [Xcode 8.1 Release Notes](https://developer.apple.com/library/content/releasenotes/DeveloperTools/RN-Xcode/Introduction.html)

また、[Swift-Evolution Proposal Status](https://apple.github.io/swift-evolution/) を見ると、さらに細かい動向が分かります。

- 上にあげたものの他に、[SE-0140: Availability by Swift version](https://github.com/apple/swift-evolution/blob/master/proposals/0141-available-by-swift-version.md) もSwift 3.1 に実装済みであること
- 実装中のものがいくつかあること(Swift 3.1 に入るとは限らない？)
- 取り入れることは決まったが、まだ実装着手前のものがあること(Swift 3.1 に入るとは限らない)

## Swift 3.1はいつリリースされる？

**未定です**が、これまでのリリースサイクル見ると、2017年3月頃に Xcode 8.3 とセットでリリースされるかな？と予想しています。(完全に予想です)

【追記】
この記事を書いた後にアナウンスされた[Swift.org - Swift 3.1 Release Process](https://swift.org/blog/swift-3-1-release-process/#source-compatibility) に「2017年春」と記載されていました。

# Swift 3.1 の機能はどうやって試せば良い？

いくつか方法があります。

## 方法1: Swift のサイトからダウンロード

[Swift.org - Download Swift](https://swift.org/download/#previews) から開発版をダウンロード出来ます。
今の正式最新版はSwift 3.0.1 ですが、開発版の Swift にも種類があるということに注意です。

- 3.0 系のベータ(次は 3.0.2 )
  - `swift-3.0-branch` ブランチ上で適宜タグ(`swift-3.0.2-PREVIEW-1` など)が切られている
- 開発最新版である `master` ブランチの Snapshots
  - `master` 上で、タグ(`swift-DEVELOPMENT-SNAPSHOT-2016-12-01-a` など)が切られている
  - 現時点では `swift-3.1-branch` と乖離していないので、実質3.1開発版とみなせる状態

というわけで、Swift 3.1 を使いたい場合は、[Snapshots最新版](https://swift.org/download/#snapshots) からダウンロードすれば良いことが分かります。
ダウンロード・インストール後、このようにツールチェーンを Snapshot 版に設定すれば Swift 3.1 の開発版を使えるようになります。

<img width="307" alt="1.png" src="https://qiita-image-store.s3.amazonaws.com/0/19398/9995130a-4a10-aaf1-77f6-d896f58e097f.png">

ちなみに、前者の「3.0 系のベータ(次は 3.0.2 )」は以下で配布されているものを使うのが良いと思います:
[Download - Apple Developer](https://developer.apple.com/download/)

## 方法2: 自力で Swift をビルドする

以下を参考に自力でビルドする方法もあります。

- [オープンソースになったSwiftをビルドしてみる - Qiita](http://qiita.com/shu223/items/99b5ecc0ac5af2566c9c)
    - 1年前 Swift がオープンソース公開された直後の記事なのでそのまま実行してもうまくいかないかもしれませんが、充分参考にはなります
- [apple/swift: The Swift Programming Language](https://github.com/apple/swift#getting-started)

ちなみに、僕は以前はすんなりビルド成功しましたが、今久しぶりにやったら失敗してしまい、公式ドキュメントをなぞりながら少しだけトライしましたが、うまくいかず一旦放棄しました(今特にビルドしたい理由が無かったのであっさり断念)。

## 方法3: [IBM Swift Sandbox BETA](https://swiftlang.ng.bluemix.net) を使う

[IBM Swift Sandbox BETA](https://swiftlang.ng.bluemix.net) で済めば一番お手軽なので、オススメです。
今の Xcode beta としても配布されていないレベルのバージョンでがっつり開発したいことは通常無いはずで、ちょっとしたコードを試してみたい程度のことがほとんどのはずですし。
このように、ある程度先のビルドが試せます(現時点での最新は12月9日のスナップショット相当)。

<img width="305" alt="2.png" src="https://qiita-image-store.s3.amazonaws.com/0/19398/bc94dce7-3f23-2498-f5a4-7324d36f9b2d.png">


方法1で取得出来る最新版と比べて少し古めですが、試してみたい機能が運良くこれに含まれていたらこの方法で検証するのが一番楽ですね。
(そもそもLinux版ということで通常の macOS・Xcode で使っている Swift と微妙な挙動の差があるかもしれないことに注意ですが。)

ただ、コード補完があまり効かないこと・評価結果の自動出力が無いことなど、XcodeのPlaygroundと比べて劣る点もいくつかあります。

# [SR-1009: Add methods to an Array containing a specific type](https://bugs.swift.org/browse/SR-1009) を試してみる

`Optional<String>` (`String?`) に、ちょっとした便利メソッドを生やしてみましょう。

```swift
extension Optional where Wrapped == String {
    /** 値があればそれを返して無ければ空文字を返す */
    var getOrDefault: String {
        return self ?? ""
    }
    /** nilや空文字の場合はtrue、それ以外の時はfalseを返す */
    var isNilOrEmpty: Bool {
        return self?.isEmpty ?? true
    }
}
```

上のは素直な実装ですが、Swift 3.0では `where Wrapped == String` の箇所で次のコンパイルエラーが出てしまいます(´・︵・｀)

```
Same-type requirement makes generic parameter 'Wrapped' non-generic
```

(こちらで確認出来ます: http://swiftlang.ng.bluemix.net/#/repl/58464c1a28620350e04560fa )

Swiftはジェネリクスの制約が多いです。
参考: [Safx: Swift 2.1のジェネリクスでできないことまとめ](http://safx-dev.blogspot.jp/2016/03/swift-21.html)

というわけで、Swift 3.0 で書くとしたら、次のように面倒な実装となってしまいます。
(もう少し簡単な書き方ご存じでしたら教えてください)

```swift
protocol StringProtocol {
    var value: String { get }
}
extension String: StringProtocol {
    var value: String { return self }
}

extension Optional where Wrapped: StringProtocol {
    /** 値があればそれを返して無ければ空文字を返す */
    var getOrDefault: String {
        return self?.value ?? ""
    }
    /** nilや空文字の場合はtrue、それ以外の時はfalseを返す */
    var isNilOrEmpty: Bool {
        return self?.value.isEmpty ?? true
    }
}

var s: String? = nil
s.getOrDefault // ""
s.isNilOrEmpty // true

s = "(　´･‿･｀)"
s.getOrDefault // (　´･‿･｀)
s.isNilOrEmpty // false
```

(こちらで確認出来ます: http://swiftlang.ng.bluemix.net/#/repl/58466c4b28620350e045610d )

局所的に対処すれば良いので許容範囲ですが、あまり本質的で無い書き方を余儀なくされてちょっと残念ですね。

余談ですが、わざわざ便利メソッド生やさなくても以下で良い気もします。この程度の処理の場合、どちらが良いか迷ってます🤔

```swift
s ?? ""
s?.isEmpty ?? true
```

## [SR-1009: Add methods to an Array containing a specific type](https://bugs.swift.org/browse/SR-1009) でこれが解決しました🎉

Swift 3.1 で、初めに書いた直感的なコードのコンパイルが通るようになります🎉

これは11月1日時点で実装済みだったため、IBM Swift Sandbox でも試せるので、こちらで確認出来ます: 
http://swiftlang.ng.bluemix.net/#/repl/58464c7528620350e04560fb

# Swift 3.1 に備えて

今ジェネリクスの制約もそうですが、現状の言語仕様の制約で将来改善されることが明らかなものに関しては、`TODO: Swift 3.1で直す` など添えておくと、後でキレイなコードに直しやすくて良いかなと思いました。

## Swift 3.1 からは `@available(swift, obsoleted: 3.1)` が使える

Swift 3.1 に[SE-0140: Availability by Swift version](https://github.com/apple/swift-evolution/blob/master/proposals/0141-available-by-swift-version.md) が入るので、例えば以下のように書くと、そのクラスが3.1 以降では利用出来なくなることを予め明示出来ます。

```swift
@available(swift, obsoleted: 3.1)
class MyClass {}
```

ただ、Swift 3.0 には入っていないので、今使うと以下のように警告が発生してしまいます。
(成果物に影響しないとはいえ、警告を気にせず使うのは良くないですよね🤔)

```
Unknown platform 'swift' for attribute 'available'
```

本当は、上で定義した `StringProtocol` に付けて Swift 3.1 に備えられるとベストでしたが…。

とはいえ、Swift 3.1 で `@available` 属性にこの指定もできるようになるので、Swift 3.2以降に向けてはこの方法は便利に使えそうです👀

---

Swift 3.1 についての話は気が早いかもしれませんが、今後どうなっていくのかたまに確認しておくと見通しよくなります。少し前まで(2015年11月以前)は、 Swift の今後についてブラックボックスでしたが、オープンソース化されてこのように把握出来る状態になってとても良かったです(　´･‿･｀)
Swift は今後、破壊的変更はかなり限定的になるはずですが、キレイなコードを保つにはやはり適宜既存コードの書き換えした方が良い場面も出てきそうに思いました。