Swift Digest
SE-0001 | Swift Evolution

Allow (most) keywords as argument labels

Proposal
SE-0001
Authors
Doug Gregor
Review Manager
Status
Implemented (Swift 2.2)

01 何が問題だったのか

Swiftの引数ラベルは、関数のインターフェイスの一部としてその引数の役割を表し、呼び出し側の可読性を高める重要な要素です。ところが、ある引数にとって最も自然なラベルが、inrepeatdefer のような言語キーワードと一致してしまうことがあります。

キーワードをラベルにできず、不自然な命名を強いられる

たとえば、コレクションの中から特定の値のインデックスを探すモジュールスコープの関数を考えると、indexOf(_:in:) のようなシグネチャが自然です。呼び出しは次のように書きたくなります。

indexOf(value, in: collection)

しかし in はキーワードなので、引数ラベルとして使うにはバッククォートでエスケープしなければなりませんでした。

indexOf(value, `in`: collection)

この煩雑さを避けるため、API作者は within のような別の単語で妥協しがちで、本来もっとも自然なラベルが使えないという状況が生まれていました。

Objective-C API のインポートで特に問題になる

この問題は、Objective-C のAPIを「不要な語を省く」ヒューリスティクスに従ってSwiftに取り込むときに顕著になります。インポートの結果として inprotocol のようなキーワードがラベル位置に現れるケースが多く、呼び出し側は常にバッククォートを書かされることになります。

event.touchesMatching([.Began, .Moved], `in`: view)
NSXPCInterface(`protocol`: SomeProtocolType.Protocol)

簡単な調査でも、キーワードと衝突するインポートAPIは200近くにのぼり、そのうちの約9割が in でした。結果として、ユーザーはあらゆる呼び出し箇所でバッククォートを書くか、APIを別名にリネームするかを迫られることになり、エコシステム全体の書き味を損ねていました。

02 どのように解決されるのか

inout / var / let を除くすべてのキーワードを、引数ラベルとしてバッククォートなしで使えるようにします。これにより、inrepeatprotocol のような自然な語をそのままラベルに選べるようになります。

呼び出し側

もっとも重要なのが呼び出し式です。引数リスト内ではキーワードの直後に : が続くため文法的な曖昧さがなく、バッククォートなしで書けるようになります。

indexOf(value, in: collection)
event.touchesMatching([.began, .moved], in: view)
NSXPCInterface(protocol: SomeProtocolType.self)

関数・サブスクリプト・イニシャライザの宣言

宣言側でも、除外された3つのキーワード以外はラベルとして使えるようになります。ラベルの後には識別子・:_ のいずれかが続くため、文法的な曖昧さはありません。

func touchesMatching(phase: NSTouchPhase, in view: NSView?) -> Set<NSTouch>

一方、inout / var / let は引数宣言そのものを修飾するキーワードであり、従来の意味を保つ必要があるため、引き続きラベルとして使うにはバッククォートが必要です。

func addParameter(name: String, `inout`: Bool)

関数型

関数型の表記でも同じルールが適用されます。パラメータ名の直後は必ず : なので、宣言側よりもむしろ単純です。

(NSTouchPhase, in: NSView?) -> Set<NSTouch>
(String, inout: Bool) -> Void

既存コードへの影響

この変更は純粋な追加であり、既存コードの挙動は何も変わりません。これまでill-formedだった書き方の一部が新たにwell-formedになるだけなので、移行の心配なく恩恵を受けられます。