Swift 2.2 の新機能: SE-0022: メソッドの Objective-C のセレクタの参照

[Swift 2.2 Released!](https://swift.org/blog/swift-2-2-released/) より [SE-0022: メソッドの Objective-C のセレクタの参照](https://github.com/apple/swift-evolution/blob/master/proposals/0021-generalized-naming.md) です。
個人的には今回一番嬉しい変更でした。
原文に従ってこの訳は [Apache License 2.0](https://github.com/apple/swift-evolution/blob/master/LICENSE.txt) とします。
ツッコミお待ちしています。

# メソッドの Objective-C のセレクタの参照

* 提案: [SE-0022](https://github.com/apple/swift-evolution/blob/master/proposals/0022-objc-selectors.md)
* 著者: [Doug Gregor](https://github.com/DougGregor)
* ステータス: **受理された**
* レビューマネージャ: [Joe Groff](https://github.com/jckarter)

## はじめに

Swift 2 では Objective-C のセレクタは `Selector` の型コンテキスト(訳注:ソースコード中で `Selector` 型のものを記述できる箇所)で文字列リテラル(例えば `"insertSubview:aboveSubview:"`)を使って記述されます。この提案ではこのようなエラーを起こしやすい方法を Swift の名前でメソッドを参照する `Selector` 初期化構文で置き換えることを模索します。
　
Swift-evolution のスレッド: [こちら](http://thread.gmane.org/gmane.comp.lang.swift.evolution/1384/focus=1403)

## 動機

セレクタの名前を文字列で指定すると、とても簡単にエラーを引き起こします: その文字列が存在するメソッドかどうか、意図したクラスのメソッドかどうかチェックしないだけでなく、セレクタとして文法的に正しいかどうかすらチェックしません。さらには[Objective-C の API の名前は自動的に変更](https://github.com/apple/swift-evolution/blob/master/proposals/0005-objective-c-name-translation.md)されるので、Swift での名前と Objective-C のセレクタの対応は自明ではありません。Swift の名前で明示的に"セレクタを作る"構文を用意することで開発者が実際の Objective-C のセレクタを使わなければならない理由を無くします。

## 提案手法

メソッドの参照からセレクタを作る `#selector` という式を新しく導入します。例:

```swift
control.sendAction(#selector(MyApplication.doSomething), to: target, forEvent: event)
```

の "doSomething" は MyApplication のメソッドです。実は Objective-C では全く関係のない名前を持っているものかもしれません:

```swift
extension MyApplication {
  @objc(jumpUpAndDown:)
  func doSomething(sender: AnyObject?) { … }
}
```

Objective-C のセレクタを生成する `#selector` 式と Swift のメソッド名での指定により開発者は自分で名前の変換を行う必要がなくなり、メソッドが実際に存在し、Objective-C に公開されているものかどうか静的のチェックできるようになります。

この提案は[引数ラベルを含めた関数の名前付けに関する提案](https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160111/006262.html)を含んでおり、その提案の引数ラベルも使ってメソッドを名前付けします。例:

	let sel = #selector(UIView.insertSubview(_:atIndex:)) // produces the Selector "insertSubview:atIndex:"

`#selector` 構文の導入と合わせてセレクタを作るための文字列リテラルの使用を廃止予定とするべきです。理想的には Swift 2.2 で廃止予定扱いにし、Swift 3 で完全に廃止できるでしょう。

加えて、文字列リテラルによるセレクタからメソッドの指定への変換をサポートする専用のマイグレータを導入するべきです。これをうまく行うためには特定の Objective-C のセレクタに付随するすべての宣言を見つけ、どれを参照しているのか特定することをコンパイラ/トランスレータに要求するため単純なことではありません。しかし、これは実現可能なはずで、他の参照も特定の、文字列を使った初期化構文(例: `Selector("insertSubview:atIndex:")`)にマイグレートできます。

## 詳細設計

`#selector` 式の部分式は `objc` メソッドの参照でなければなりません。特に入力式は Objective-C のメソッドへの直接的な参照でなければなりません。括弧で囲われているか可能性があり、as キャスト(Swift の同名のメソッドの曖昧さを解決するため使用することができる)が使われている可能性もあります。

```swift
let sel = #selector(((UIView.insertSubview(_:at:)) as (UIView) -> (UIView, Int) -> Void))
```

部分式は評価されず、式が副作用を起こさない点に注意してください。

## 既存のコードに対する副作用

`#selector` 式の導入は既存のコードに影響しません。しかし、文字列リテラルによるセレクタを廃止予定扱いにし、廃止することはソースコードの互換性を損なう変更です。新しい、`#selector` 式か、文字列による `Selector` の明示的な初期化のいずれかに移行できます。

## 検討された代替案

第一の代替案は[型安全なセレクタ](https://lists.swift.org/pipermail/swift-evolution/2015-December/000233.html)です。これは `@objc` メソッドとそのセレクタの型をキャプチャする新しい "selector" 呼び出し規約を導入するものです。

```swift
@convention(selector) (MyClass) -> (NSNotification) -> Void
```

セレクタを受け取る Objective-C の API は型情報を提供することができたでしょう(例: Objective-C のアトリビュートまたは型情報付きの新しい `SEL` 構文によって)。これはセレクタベースの API の型安全性を向上させます。個人的には型安全なセレタクはよく設計された機能ではありますが、実現するほどの価値があるとは思いませんでした。既存の Objective-C の API との相互互換性を向上させる目的以外ではおそらく使われなかったでしょう。一般にクロージャを使ったほうが好ましい(Swift にとっても Objective-C にとっても)からです。この機能を追加するコストは Swift と Clang の両方にとって非常に大きなものです。そしてこの機能が役に立つようにするには膨大な数の Objective-C の API でこの機能をサポートする必要があったでしょう。iOS の場合、私たちは比較的少数の API (100ちょっと)の API について議論しています。その多くはどのみちより好ましいブロック/クロージャを使用するバージョンを持っています。それため、複雑(ですが、より型安全であることは認めます)な代替案よりもこの提案のよりシンプルな機能を実装するべきです。

文法的な観点からすると、`@selector(method reference)` は Objective-C とより強く一致したでしょう。しかし、`@` が常にアトリビュートを表すわけではない Swift では妥当ではありません。

この提案のオリジナルのバージョンでは魔法のような `Selector` イニシャライザを提案しました。

```swift
let sel = Selector(((UIView.insertSubview(_:at:)) as (UIView) -> (UIView, Int) -
```

しかし、この魔法のような文法がインスタンスの構築(しかし実際には Swift のイニシャライザを表さない)
に見えること、さらに、特別な式であることを示すためにすでに `#` を使っている(例: `#available`)点に関心が集まり、`#selector` を使用する文法に変更することがパブリックレビューの完成時に決まりました。