Swift Digest
SE-0122 | Swift Evolution

Use colons for subscript declarations

Proposal
SE-0122
Authors
James Froggatt
Review Manager
Chris Lattner
Status
Rejected

01 何が問題だったのか

Swift の subscript 宣言は、関数と同じく -> で戻り値の型を示す構文になっていました。

subscript(externalName internalName: ParamType) -> ElementType {
    get { ... }
    set { ... }
}

しかし subscript は実際には「引数付きのプロパティアクセサ」に近い存在です。通常のプロパティと同じように代入式の左辺に置けますし、subscript 経由でアクセスした値をその場でミュータブルに書き換えることもできます。

それにもかかわらず関数の -> を流用していることで、次のような違和感や誤解を生みやすいと指摘されました。

  • 関数から借りてきた -> は、パラメータ付きアクセサという文脈では浮いてしまい、読み手の思考のつまずきになります。
  • -> を見ると「subscript も関数と同じ能力(例えば throws のような効果)を持つのでは」と誤解させかねません。仮に将来アクセサに効果を付けられるようになった場合、効果は個々の get / set に付くのが自然であり、関数風の「シグネチャ」に書くべきものではなくなります。

一方で、プロパティや型注釈、辞書リテラルの「ラベルと型」など、Swift では「名前と型を結び付ける」場面で : を使う慣習が既に確立されていました。subscript をプロパティ系の宣言として捉えるなら、戻り値の型を表す記号としても : のほうが筋が通ります。

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

subscript 宣言の ->: に置き換え、プロパティの型注釈と同じ記法で戻り値の型を書けるようにすることが提案されました。

subscript(externalName internalName: ParamType) : ElementType {
    get { ... }
    set { ... }
}

既存のコードは ->: に機械的に置き換えるだけで移行でき、Swift 3 への構文変換として自動化できるとされていました。

このProposalの結論

この提案は Rejected となりました。Swift コアチームは過去に内部で同様の変更を試したことがあり、そのときは可読性の低下を理由に見送られた経緯があります。Proposal 自身も「読みやすさへの影響は予測しづらい」ことを潜在的な懸念として挙げています。

特に問題になるのは、閉じ括弧の直後にスペースを空けずに : を置くスタイルです。

subscript(_ example: Type): ElementType

このように書くと :) に溶け込んで見え、型注釈の開始が視認しづらくなります。subscript 宣言自体が比較的まれな構文であることも相まって、-> から : への変更で得られる一貫性は、読みづらさの増加に見合わないと判断されました。

Future Directions(参考)

Proposal では、もし : 表記が採用されれば、将来的に「パラメータ付きのアクセサ構文」を名前付きアクセサへ拡張する余地も生まれると触れられていました。たとえば次のような、subscript ではなくプロパティ名側にパラメータを取る記法です。

var image(for state: UIControlState) : UIImage? {
    get { ... }
    set { ... }
}

button.image(for: .normal) = image

ただしこれはあくまで将来の可能性として示されていたものに過ぎず、本提案自体が Rejected となったため、現時点では実現が約束された方向性ではありません。