Swift3が落ち着いて、そろそろSwift4に向けてウォームアップを考え始めなくてはいけない頃ではないでしょうか。そう、休みなんてないんです😭 Swift Evolutionの見やすいサイトができていい機会だったので、2017.1.27時点の Accepted で未実装のものをまとめたいと思います。
SE-0068 Expanding Swift Self to class members and value types
Swift3.0からは dynamicType
から type(of:)
になった自身のクラスまたは型を取得する方法が Self
で可能になります。下記のようなスタティックメソッドをインスタンスメソッドから使用する際に、名前が長いとうんざりしてたので地味に嬉しいです。
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
Unapplied Method Reference (インスタンスメソッドを型から直接呼び出して関数として得るもの)の返り値がフラットな状態で受け取れるようになります。通常カーリー化では f(1)(2)
のように関数を引数として受けとるので現状が正しいように思えますが、Swiftの場合は reduce(0, +)
のように引数を並べて受け取るように作られているので、そこに合わせるといった感じでしょうか。
下記のように map
に Unapplied Method Reference をそのまま渡しても、関数のネストがひとつ深いのでエラーが出てしまします。
func sortedArrays<T: Comparable>(arrays: [[T]]) -> [T] {
// Error: `map` expects [T] -> [T], but
// `Array.sorted` has type ([T]) -> () -> [T]
return arrays.map(Array.sorted)
}
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
今まで使える機能(モジュール)は #if !os(OSX)
のようにOSで判定するしかなかったのですが、今後そのOSにモジュールが対応した場合コードの改修が必要になり、アップデートの多いSwiftでは脆い実装になりがちです。そこで下記のように canImport(Cocoa)
でそのモジュールが使用できるか判定できるようになります。
# if canImport(UIKit)
// UIKit-based code
#elseif canImport(Cocoa)
// OSX code
#elseif
// Workaround/text, whatever
# endif
SE-0104 Protocol-oriented integers
Swiftの整数のプロトコルはジェネリクスに適したものではないみたいで Int8
や Int16
などを受け取る整数型のジェネリクスな引数を受け取る処理などを書くのは容易ではありませんでした。このブログでは整数にジェネリクスアルゴリズムを持たせようと試みてます。
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
associatedtype
に where
句が付けられるようになります。これは結構嬉しい状況が出るのではないでしょうか。例えば Sequence
プロトコルに準拠した associatedtype
を宣言する時に中身の Element
の型を指定したい場合などは下記のように書くことができます。関数のジェネリクスと同じ挙動になるので扱いやすくなりそうです。
protocol Foo {
associatedtype Bar: Sequence where Bar.Iterator.Element == Int
func baz() -> Bar
}
また、上記の修正で下記のようにプロトコル宣言時にも where
句を使えるようになるみたいです。
protocol Foo : Sequence where Iterator.Element == Int { ... }
しかし、このプロトコル宣言時に使える where
句は親のプロトコル(この場合 Sequence
)に関連している型やプロトコルのみ指定できます。以下のコードではエラーになるので、その時は associatedtype
を使えばいいみたいです。
// 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
型の拡張をする時に where
句を使って、ある条件下の時のみ拡張できるようになります。例えば Array
の中身の Element
が Equatable
に準拠しているのであれば Array
自体も Equatable
に準拠させるようにできます。
extension Array: Equatable where Element: Equatable {
static func ==(lhs: Array<Element>, rhs: Array<Element>) -> Bool { ... }
}
※ 現状の Array
でも比較演算子が使えるのは下記の関数のジェネリクスを使って実装されているからです。これよりも上記の条件付き拡張の方がどんな Array
であれば比較演算子がつかえるのか分かりやすいです。
public func ==<Element : Equatable>(lhs: ContiguousArray<Element>, rhs: ContiguousArray<Element>) -> Bool
SE-0142と合わせてみると型チェックが動的に行えるような仕組みが提供されている気がします。今までは Type Erasure のような魔法が使われてきましたが、今後は意識しないでも自然に動的な型チェックができるようになるのかもしれないです。ここで今後のジェネリクスのマニフェストが公開されているので覗いてみてもいいかもです👏