おはようございます。シニアアプリケーションエンジニアの id:cockscomb です。WWDC が目前に迫ったいま、今秋にリリースが予定されている Swift 3.0 について、Swift OSS コミュニティの中心である Swift Evolution から読み取っていきたいと思います。
[PR]
本記事は、筆者が株式会社はてなの協賛を得て主催した「関西モバイルアプリ研究会 #14」において、“Swift Otaku — Nerdy Swift-Evolution Watching” と題して発表したものをブログの記事として再構成したものである。
関西モバイルアプリ研究会は、毎月一度、平日夜に京都や大阪で開催される、モバイルアプリ関連の勉強会である。次回の「関西モバイルアプリ研究会 #15」は6月22日水曜日に開催予定だ。
目次
Swift 3.0 はこの秋にリリースが予定されている。Swift 3 Release Process から考えると、1週間後の Apple World Wide Developers Conference (WWDC) 2016 に合わせて最初の Developer Preview バージョンがリリースされるはずだ。オープンソース化されたとはいえ、基本的には Apple のスケジュールに左右される。Swift 3.0 はいったいどのようなアップデートになるのだろうか。
OSS になった Swift は、swift-evolution メーリングリスト での議論や、GitHub の Swift Evolution にまとめられた proposal によって、将来の変更を決定している。これらを追うことで、Swift 3.0 やその先のリリースについて知ることができる。
Focus
Swift Evolution によれば Swift 3.0 は以下のことに焦点を当てるとされる。
- API design guidelines
- Automatic application of naming guidelines to imported Objective-C APIs
- Adoption of naming guidelines in key APIs
- Swiftification of imported Objective-C APIs
- Focus and refine the language
- Improvements to tooling quality
このほか portability もまた重要であることが明言されている。Swift Evolution で議論される proposal は、基本的にはこれらのトピックに関連しているはずだ。
ところで、当初 Swift 3.0 での目標とされていたいくつかのトピックが削除されていることに気付くだろうか。
Winding Down
5月半ばに Chris Lattner は、“Winding down the Swift 3 release” と題したメールをコミュニティに送った。そこには ABI の安定化と、そのために必要な generics の機能を完成を、Swift 3.0 のリリースから見送ることが書かれている。また Swift 3.0 では API naming という困難に向き合い、ソースコードレベルでの安定化が図られたということが強調されている。つまり将来のバージョンの Swift でも、可能な限りソースコードの互換性が維持されることが期待されている。そして、Swift 3.0 以降の 3.x や 4.0 については、今年の8月以降に議論を再開するとされた。
コミュニティからは ABI の安定化が見送られることについてネガティブな反応が見られたが、Chris Lattner を含む Swift Core Team は丁寧にそれに答えている。Objective-C の時代に起きた ABI に関する問題の例を挙げて、スケジュール上の圧力が ABI に問題を引き起こすのを避けるためには急ぐべきではないことを説明している。
ところで今回は見送られた generics の完成や ABI の安定化とは何だろうか。本論からは少し脱線するが、簡単に覗いてみよう。
Complete Generics
標準ライブラリの ABI を安定させるためには、標準ライブラリで本来は利用したいと考えられる generics の機能を実装する必要がある。“Generics Manifesto” と題されたドキュメントは、元は Swift Evolution のメーリングリストに投稿されたものであるが、そういった generics の展望を示したものである。Generics が拡張されることで、Swift の表現力もさらに改善される。
ABI Stability
Swift における Application Binary Interface (ABI) の安定とはつまり、異なるバージョンの Swift コンパイラでコンパイルしたバイナリがリンクできる状態である。このために Swift は、言語機能の重要な部分を確定させると共に、実行時のデータ構造や呼び出しの規約などを仕上げなければならない。標準ライブラリについてもそのインターフェースを確定させる必要がある。
ABI の安定化と共に、Resilience と呼ばれる機能も必要とされている。Resilience (弾力) は Fragile (壊れやすい) に対応する語として使われている。Swift で書かれたライブラリが ABI 上の互換性を保つための機能である。
例えばライブラリの公開インターフェースとなっている struct に、新たに stored property を追加したらどうなるだろう。あるいは enum に後から case
を追加できるとしたら、網羅性の検査に影響があるのではないか。
今のところの計画では、ライブラリはその API をバージョニングできるようになる。また stored property の追加やその定義順の変化は ABI を壊すことなく実現可能である。enum についても通常は case
の追加を許容するが、case
の追加が起きない @closed
な enum を作ることもできる。一般に、後から変えても ABI 上の互換性を保つことは実行時のパフォーマンスに影響するが、必要な場合にこれを解消できるように、@inlinable
な関数や @fixed_contents
な struct を作ることもできる。
このような内容は “Library Evolution” と題されたドキュメントにまとめられている。ただしこれらは Swift Evolution での議論を経ておらず、実現する際にはいくらか違ったものになっているかもしれない。
Proposals
本題に戻って、Swift 3.0 に関して Swift Evolution でこれまでに議論されてきた proposal の中から、いくつか興味を惹かれるものを見ていこう。
Naming Guidelines
- SE-0023 API Design Guidelines (Accepted)
- SE-0006 Apply API Guidelines to the Standard Library (Accepted)
- SE-0005 Better Translation of Objective-C APIs Into Swift (Accepted)
Swift の新しいネーミングガイドラインに関する proposal は多い。その中でも上記の3つが基本的なものである。新しいガイドラインは “API Design Guidelines” としてまとめられており、それを標準ライブラリや Objective-C からのインポートにも適用するところまでがこれらである。
関連する proposal は他にもある。
- SE-0033 Import Objective-C Constants as Swift Types (Accepted)
swift_wrapper
属性で Objective-C の定数を enum や struct にする
- SE-0044 Import as member (Accepted)
swift_name
属性で C の struct を引数にとるグローバル関数をその struct のメンバーにする
- SE-0046 Establish consistent label behavior across all parameters including first labels (Accepted)
- 関数の第一引数のラベルを一貫させる
- SE-0059 Update API Naming Guidelines and Rewrite Set APIs Accordingly (Accepted)
- 破壊的なメソッドと新しい値を返すメソッドのペアがあるときについてのメソッド名のガイドラインの変更で、動詞と名詞の使い分けの他に、from prefix パターンを付け加えた
この中でも SE-0044 Import as member は、例えば Core Graphics などのフレームワークに見られる CGContextSetLineWidth(_:_:)
のような、第一引数に(オブジェクト指向のイメージではメソッドのレシーバに相当する)struct への参照をとる(この場合は CGContextRef
)関数を、context.lineWidth = width
のようなフォームへ変えられる。Objective-C だけでなく、C の API まで Swift らしくすることができ、画期的である。
Core Libraries
Swift 3.0 では、Apple 以外のプラットフォーム向けにも Core Libraries として Foundation/Grand Central Dispatch/XCTest の3つが提供される。これに伴う proposal もいくつか存在している。
- SE-0069 Mutability and Foundation Value Types (Accepted)
- SE-0086 Drop NS Prefix in Swift Foundation (Under Review)
実は SE-0005 Better Translation of Objective-C APIs Into Swift の proposal には当初、Foundation から NS prefix を取り除くことが盛り込まれていた。しかし rationale にあるように、参照型のセマンティクスを持つ Foundation と値型のセマンティクスを持つ標準ライブラリの矛盾といったことを含むいくつかの理由からいったん見送られていた。
SE-0069 Mutability and Foundation Value Types では Foundation のいくつかの class について対応する struct を導入する。例えば NSDate
と Date
のように、NS prefix の取り除かれた struct の導入で値型のセマンティクスを得る。
SE-0086 Drop NS Prefix in Swift Foundation は、ついに NS prefix を取り除こうという proposal である。基本的な方針は、Objective-C ランタイムと関連していたり、Apple のプラットフォームと関連していたりするものは NS prefix を残し、あとは prefix を削除するというものである。現在まだレビュー中であるが、多少議論が分かれている。
Grand Central Dispatch (GCD) の API を Swift らしくしようというのがこの proposal である。GCD はもともと C で API を提供しているが、例えば dispatch_queue_t
型を DispatchQueue
型にしたり、グローバル関数をメソッドにしたりすることで、より Swift らしいインターフェースに変えるというものだ。
Objective-C
- SE-0057 Importing Objective-C Lightweight Generics (Accepted)
- Objective-C の Lightweight Generics を Swift から利用する
- SE-0062 Referencing Objective-C key-paths (Accepted)
- Key Value Coding (KVC) や Key Value Observing (KVO) で利用される key path 文字列を、
#keyPath()
式でコンパイル時に検証できるようにする
- Key Value Coding (KVC) や Key Value Observing (KVO) で利用される key path 文字列を、
- SE-0064 Referencing the Objective-C selector of property getters and setters (Accepted)
#selector()
式を拡張して#selector(getter:)
や#selector(setter:)
などを導入し、property の getter や setter を参照できるようにする
- SE-0070 Make Optional Requirements Objective-C-only (Accepted)
- protocol の
optional
指定を@objc
属性に限定する
- protocol の
Objective-C で書かれたコードとのインタラクションも Swift 3.0 ではさらに改善される。可能な限りコンパイル時に検証しようとするのは良いことである。
ところで、Objective-C の class でも property が利用できるようになる予定である。Swift のバグトラッカーに登録された Unknown property attribute 'class' を見ると(すでに修正されたが)、そのことがわかる。Apple Clang コンパイラは将来のバージョンで Objective-C class properties をサポートする予定だ。このように、Objective-C もまた Swift に合わせて進化しようとしている。
Swift Package Manager
- SE-0019 Swift Testing (Accepted)
- パッケージの
Tests
ディレクトリ以下にテストコードを置いておき、CUI で実行可能にする
- パッケージの
- SE-0038 Package Manager C Language Target Support (Accepted)
- C/C++/Objective-C/Objective-C++ で書かれたモジュールを Swift から使えるようにビルドする
- SE-0063 SwiftPM System Module Search Paths (Accepted)
- システムにインストールされたライブラリへのパスを解決するために
pkg-config
の.pc
ファイルを読み込めるようにする
- システムにインストールされたライブラリへのパスを解決するために
- SE-0082 Package Manager Editable Packages (Accepted)
- 依存しているパッケージを同時に開発するワークフローをサポートする
- SE-0085 Package Manager Command Names (Accepted)
- Package Manager のコマンドを
swift package
のサブコマンドとする
- Package Manager のコマンドを
Swift のエコシステムを強化するため Swift 3.0 から新たにツールチェーンに加わる Swift Package Manager (SwiftPM) もまた、活発に議論されている分野である。リリース前であるにも関わらず、専ら実用性を意識した proposal が多いようにみられるが、これはコミュニティの期待感のあらわれではないだろうか。
クローズドソースの Xcode が今年の WWDC 以降にどれくらい SwiftPM と連携していくのか、そういった期待もある。
Swift Language
純粋なプログラミング言語としての Swift にも、様々な変化が待っている。
可視性のスコープ
- SE-0025 Scoped Access Level (Accepted)
シンボルの可視性が整理される。Swift 2.2 までの private
は、それが書かれたソースファイルの中からだけ参照できるというものだった。Swift の extension
機能には便利な場面がある一方で、他の言語とは一貫しない仕様である。Swift 3.0 からは、このような可視範囲を fileprivate
として、新たにその定義中でのみ可視の private
を加えた。これによって Swift の可視性のスコープは以下の4つになる。
キーワード | 可視性 |
---|---|
public |
モジュールの外部まで可視 |
internal |
モジュールの内部だけに可視 |
fileprivate |
そのファイルの中だけに可視 |
private |
現在の定義の中だけに可視 |
関数
- SE-0029 Remove implicit tuple splat behavior from function applications (Accepted)
- 関数の引数列と型やラベルが合っているタプルを関数の引数として渡せるのをやめる
- SE-0047 Defaulting non-Void functions so they warn on unused results (Accepted)
- 返り値のある関数の返り値を利用していないとデフォルトで警告する(これまでの
@warn_unused_result
アノテーション相当)し、実際に利用する必要がない場合は_ =
で返り値を受けることを半強制する。また返り値を必ずしも利用する必要がない関数には@discardableResult
アノテーションをつけられるようにする
- 返り値のある関数の返り値を利用していないとデフォルトで警告する(これまでの
- SE-0060 Enforcing order of defaulted parameters (Accepted)
- デフォルト値のある引数が複数個あるとき、その順序を変えられないようにする
- SE-0066 Standardize function type argument syntax to require parentheses (Accepted)
- 関数型の引数では
()
の記述を必須として、(String) -> Int?
のようにする (これまではString -> Int?
のような記述も許容されていた)
- 関数型の引数では
関数については、初期の Swift で柔軟だった点を、より厳密にするような方向性の変化が多い。特にコンパイラの実装を複雑にする割にそれほど活用されていないと考えられる仕様が取り除かれている。
ImplicitlyUnwrappedOptional
ImplicitlyUnwrappedOptional
という型を Swift から無くし、!
のついた型を @_autounwrapped
属性のついた Optional
派生型として取り扱おうという proposal。暗黙的に wrap される Optional
型は、特に型システムが比較的弱い Objective-C との連携のために必要ではあるが、そのような理由がなければ代替手段によって取って代わられるべきものである。このため必要のない場面では使われないように、制限を設けようというものである。
dynamicType
- SE-0068 Expanding Swift Self to class members and value types (Accepted)
- SE-0096 Converting dynamicType from a property to an operator (Accepted)
SE-0068 Expanding Swift Self to class members and value types では、インスタンスにおいて Self
が self.dynamicType
の意味で利用できるようになる。このことでインスタンスから型の持つメンバーへのアクセスが簡単になり、構文における意味も明瞭になる。
さらに SE-0096 Converting dynamicType from a property to an operator では、インスタンスからその型を得る .dynamicType
property を dynamicType()
演算子に変える。これは dynamicType
の働きが property というよりは sizeof
などの演算子に近いのではないかという動機によるものである。
暗黙的な変換
- SE-0072 Fully eliminate implicit bridging conversions from Swift (Accepted)
- SE-0083 Remove bridging conversion behavior from dynamic casts (Deferred)
SE-0072 Fully eliminate implicit bridging conversions from Swift では、Swift 標準ライブラリの型と Foundation の型の暗黙的な変換 (String
から NSString
のような) を一切やめて、必ず as
でキャストすることになる。Swift 1.2 のときに Foundation から標準ライブラリの型への変換が無くなったが、Objective-C の lightweight generics 機能などによって多くの変換が不要になった現在では、暗黙的な変換をすべてやめたとしてもその影響は限定的であるとされた。
SE-0083 Remove bridging conversion behavior from dynamic casts はさらに、as
によるキャストで変換するのもやめ、イニシャライザを利用しようという proposal である。コミュニティからのフィードバックもポジティブである。ところが前述のSE-0072 について、Objective-C の id
型に関連して極端な問題が起きるという懸念が発生しており、これについて明確になるまでは議論が延期されている。
コンパイラ制御文
#if canImport(ModuleName)
というコンパイラ制御文によって、モジュールがインポート可能かどうかのテストを行えるようになる。
Generics
- SE-0048 Generic Type Aliases (Accepted)
- 型パラメータを持った
typealias
を定義できる。ただしあくまでもtypealias
であって、新たな型が作られるわけではない
- 型パラメータを持った
- SE-0081 Move where clause to end of declaration (Accepted)
- 型パラメータに関連する
where
節を、型パラメータの括弧 (<>
) の中ではなく、定義本体の直前にする
- 型パラメータに関連する
- SE-0092 Typealiases in protocols and protocol extensions (Accepted)
- Swift 2.2 から protocol の associated type が
typealias
ではなく専用のassociatedtype
キーワードで表すことになったので、空いたtypealias
キーワードで protocol 中でのtypealias
に利用できるようにする
- Swift 2.2 から protocol の associated type が
- SE-0095 Replace protocol<P1,P2> syntax with P1 & P2 syntax (TBD)
- 複数の protocol に準拠している型を表す
protocol<P1, P2>
構文をP1 & P2
という構文に変える。当初はAny<P1, P2>
構文が提案されていたが、P1 AND P2
ではなくP1 OR P2
と誤解する恐れがあるというコミュニティのフィードバックを受けて、論理積を表す&
演算子を使うように更新された。ただしこれは意味を明確にするためであって、論理和を表す|
演算子などは型システムがサポートできるものではない(サポートするべきではない)ことが表明されている
- 複数の protocol に準拠している型を表す
Generics Manifesto のうちのいくつかは、すでに proposal として議論が進められており、大半は承認されている。
Standard Library
- SE-0032 Add first(where:) method to Sequence (Accepted)
Sequence
から条件にマッチする最初の要素を取り出すという一般的な要求のためのfirst(where:)
メソッドを追加する
- SE-0045 Add prefix(while:) and drop(while:) to the stdlib
Sequence
の前方または後方から、条件に一致するものが続く間のSubSequence
を取り出すメソッドprefix(while:)
及びdrop(while:)
を追加する
- SE-0094 Add sequence(first:next:) and sequence(state:next:) to the stdlib (Accepted)
- グローバル関数
sequence(first:next:)
とsequence(state:next:)
の導入で高度なイテレーションを簡単に記述できるようにする。SE-0045 に含まれていながらもネーミングの問題から取り下げられた関数と同様の機能である
- グローバル関数
標準ライブラリに便利なメソッドを増やそうとするような proposal は多い。どれも一度くらいはほしいと思った機能ではないか。
さて、ここまでトピック毎に多くの proposal を見てきた。Swift 3.0 が非常に巨大なリリースであることに疑いの余地はない。とてもたくさんの点で改善される Swift 3.0 が待ち遠しいと思う。しかし同時に、既存のプロジェクトを Swift 3.0 にマイグレーションするのは骨が折れるだろう。
Swift が OSS になって約半年、信じられないスピードで変化を続ける Swift は、いまや広くコミュニティに受け入れられている。変化の早い Swift を使いこなすためには、Swift Evolution をよく観察しておくのが早道だ。
株式会社はてなでは、未来の Swift への興味が抑えきれないエンジニアを募集しています。
また、はてなサマーインターン2016では Swift を使ったモバイルアプリケーション開発が体験できます。
ふるってご応募ください。