Swift EvolutionのAcceptedステータスまとめ (2017.1.27) - Protocol-oriented integers, Permit where clauses to constrain associated types, ...etc

Swift3が落ち着いて、そろそろSwift4に向けてウォームアップを考え始めなくてはいけない頃ではないでしょうか。そう、休みなんてないんです😭 [Swift Evolution](https://apple.github.io/swift-evolution/)の見やすいサイトができていい機会だったので、2017.1.27時点の *Accepted* で未実装のものをまとめたいと思います。

# SE-0068 Expanding Swift Self to class members and value types
https://github.com/apple/swift-evolution/blob/master/proposals/0068-universal-self.md

Swift3.0からは `dynamicType` から `type(of:)` になった自身のクラスまたは型を取得する方法が `Self` で可能になります。下記のようなスタティックメソッドをインスタンスメソッドから使用する際に、名前が長いとうんざりしてたので地味に嬉しいです。

```swift
struct FooFooFooFooFoo {
    static func bar() { }
    func baz() {
        FooFooFooFooFoo.bar() // Before
        type(of: self).bar()  // Before
        Self.bar() // After
    }
}
```

# SE-0042 Flattening the function type of unapplied method references
https://github.com/apple/swift-evolution/blob/master/proposals/0042-flatten-method-types.md

*Unapplied Method Reference* (インスタンスメソッドを型から直接呼び出して関数として得るもの)の返り値がフラットな状態で受け取れるようになります。通常カーリー化では `f(1)(2)` のように関数を引数として受けとるので現状が正しいように思えますが、Swiftの場合は `reduce(0, +)` のように引数を並べて受け取るように作られているので、そこに合わせるといった感じでしょうか。

下記のように `map` に *Unapplied Method Reference* をそのまま渡しても、関数のネストがひとつ深いのでエラーが出てしまします。

```swift
func sortedArrays<T: Comparable>(arrays: [[T]]) -> [T] {

    // Error: `map` expects [T] -> [T], but
    // `Array.sorted` has type ([T]) -> () -> [T]
    return arrays.map(Array.sorted)
}
```

```swift
struct Foo {
    let x: Int
    func bar(y: Int) -> Int {
        return x + y
    }
}

let f = Foo.bar // (Foo) -> (Int) -> Int

let g = f(Foo(x: 2))(3) // Before
let g = f(Foo(x: 2), 3) // After
```

# SE-0075 Adding a Build Configuration Import Test
https://github.com/apple/swift-evolution/blob/master/proposals/0075-import-test.md

今まで使える機能(モジュール)は `#if !os(OSX)` のようにOSで判定するしかなかったのですが、今後そのOSにモジュールが対応した場合コードの改修が必要になり、アップデートの多いSwiftでは脆い実装になりがちです。そこで下記のように `canImport(Cocoa)` でそのモジュールが使用できるか判定できるようになります。

```swift
#if canImport(UIKit)
   // UIKit-based code
   #elseif canImport(Cocoa)
   // OSX code
   #elseif
   // Workaround/text, whatever
#endif
```

# SE-0104 Protocol-oriented integers
https://github.com/apple/swift-evolution/blob/master/proposals/0104-improved-integers.md

Swiftの整数のプロトコルはジェネリクスに適したものではないみたいで `Int8` や `Int16` などを受け取る整数型のジェネリクスな引数を受け取る処理などを書くのは容易ではありませんでした。[このブログ](http://blog.krzyzanowskim.com/2015/03/01/swift_madness_of_generic_integer/)では整数にジェネリクスアルゴリズムを持たせようと試みてます。

```swift
let foo: Int8 = 1
let bar = 2

// error: binary operator '<<' cannot be applied
// to operands of type 'Int8' and 'Int'
let baz = foo << bar
```

今後は以下のようなモデルの体型になるみたいです。上記のような型の違いによる演算が行えない状態を解消され、整数のどの型なのか気にしながら演算する必要がなくなります。あとは整数の拡張が容易になるみたいです。ちょっとどんな用途があるのかわかりませんが…

```
                +--------------+  +-------------+
        +------>+  Arithmetic  |  | Comparable  |
        |       |   (+,-,*,/)  |  | (==,<,>,...)|
        |       +-------------++  +---+---------+
        |                     ^       ^
+-------+------------+        |       |
|  SignedArithmetic  |      +-+-------+------+
|     (unary -)      |      |  BinaryInteger |
+------+-------------+      |  (words,%,...) |
       ^                    ++---+-----+-----+
       |         +-----------^   ^     ^-----------+
       |         |               |                 |
+------+---------++    +---------+-------------+  ++------------------+
|  SignedInteger  |    |  FixedWidthInteger    |  |  UnsignedInteger  |
|                 |    | (bitwise,overflow,...)|  |                   |
+---------------+-+    +-+-----------------+---+  ++------------------+
                ^        ^                 ^       ^
                |        |                 |       |
                |        |                 |       |
               ++--------+-+             +-+-------+-+
               |Int family |-+           |UInt family|-+
               +-----------+ |           +-----------+ |
                 +-----------+             +-----------+
 ```

# SE-0142 Permit where clauses to constrain associated types
https://github.com/apple/swift-evolution/blob/master/proposals/0142-associated-types-constraints.md

`associatedtype` に `where` 句が付けられるようになります。これは結構嬉しい状況が出るのではないでしょうか。例えば `Sequence` プロトコルに準拠した `associatedtype` を宣言する時に中身の `Element` の型を指定したい場合などは下記のように書くことができます。関数のジェネリクスと同じ挙動になるので扱いやすくなりそうです。

```swift
protocol Foo {
    associatedtype Bar: Sequence where Bar.Iterator.Element == Int
    func baz() -> Bar
}
```

また、上記の修正で下記のようにプロトコル宣言時にも `where` 句を使えるようになるみたいです。

```swift
protocol Foo : Sequence where Iterator.Element == Int { ... }
```

しかし、このプロトコル宣言時に使える `where` 句は親のプロトコル(この場合 `Sequence` )に関連している型やプロトコルのみ指定できます。以下のコードではエラーになるので、その時は `associatedtype` を使えばいいみたいです。

```swift
// error: Use of undefined associated type 'Counter'
protocol Foo: Sequence where Counter: Bar {
    associatedtype Counter
}

protocol Foo: Sequence {
    associatedtype Counter: Bar
}
```

# SE-0143 Conditional conformances
https://github.com/apple/swift-evolution/blob/master/proposals/0143-conditional-conformances.md

型の拡張をする時に `where` 句を使って、ある条件下の時のみ拡張できるようになります。例えば `Array` の中身の `Element` が `Equatable` に準拠しているのであれば `Array` 自体も `Equatable` に準拠させるようにできます。

```swift
extension Array: Equatable where Element: Equatable {
  static func ==(lhs: Array<Element>, rhs: Array<Element>) -> Bool { ... }
}
```

※ 現状の `Array` でも比較演算子が使えるのは下記の関数のジェネリクスを使って実装されているからです。これよりも上記の条件付き拡張の方がどんな `Array` であれば比較演算子がつかえるのか分かりやすいです。

```swift
public func ==<Element : Equatable>(lhs: ContiguousArray<Element>, rhs: ContiguousArray<Element>) -> Bool
```

SE-0142と合わせてみると型チェックが動的に行えるような仕組みが提供されている気がします。今までは *Type Erasure* のような魔法が使われてきましたが、今後は意識しないでも自然に動的な型チェックができるようになるのかもしれないです。[ここ](https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md)で今後のジェネリクスのマニフェストが公開されているので覗いてみてもいいかもです👏