Swift 3でクラスやメソッドにつける public や private などのアクセスコントロールが見直されました。新しいキーワードが増えただけでなく、これまでのキーワードの意味も変わったので、何がどう変わったのか、それらをどう使い分けていくのかというところを自分なりにまとめました。
これまでのアクセスコントロール
Swift 2までは次の3つのアクセスレベルがありました。何もつけなければ internal が指定されたことになります。
-
public: 同じモジュール内だけでなく、別のモジュールからでもアクセスできる -
internal: 同じモジュール内からのみアクセスできる -
private: 同じソースファイル内からのみアクセスできる
Swift 3からのアクセスコントロール
Swift 3からは次の5つのアクセスレベルになります。何も付けなければ internal になる点はこれまでと同じです。
-
open: 同じモジュール内だけでなく、別のモジュールからでもアクセスでき、別モジュールで継承またはオーバーライドができる(Swift 2までのpublicと同じ振る舞い) -
public: 同じモジュール内だけでなく、別のモジュールからでもアクセスできるが、別モジュールでは継承、オーバーライドはできない -
internal: 同じモジュール内からのみアクセスできる -
fileprivate: 同じソースファイル内からのみアクセスできる(Swift 2までのprivateと同じ振る舞い) -
private: 定義されたスコープ内でのみアクセスできる
キーワードとしては open と fileprivate が増えたわけですが、これらはそれぞれSwift 2までの public と private に相当する点に注意です。むしろ、Swift 3では public と private の意味が変わったと考えた方がいいでしょう。
新しい public がSwift 2までの public と異なるのは、別モジュールでの継承・オーバーライドを認めない点です。クラスに public を付けると、別のモジュールからでもそのクラスを使うことはできますが、そのクラスを継承することはできません。同じように、 public を付けたメソッドは、別のモジュールからでも呼び出すことができますが、継承したクラスでそのメソッドをオーバーライドすることができません。
新しい private はSwift 2までの private と異なり、それが定義されたスコープ内にしかアクセスを許可しなくなりました。こちらはJavaやC#の private に近づいた感がありますね。
どう使い分けるのか
さて、Swift 3からの5つのアクセスレベルをどのように使い分けたらいいでしょうか。
そのヒントは今回の変更点のプロポーザルにあるように思います。
-
SE-0025 Scoped Access Level ……
privateとfileprivateを分ける理由 -
SE-0117 Allow distinguishing between public access and public overridability ……
publicとopenを分ける理由
SE-0025の方には、従来の private では、完全に隠したいのか、それとも関連するコード間でのみ共有したいのかが明確でなかったということが書かれています。
SE-0117の方では、サブクラス化やオーバーライドを許すことでライブラリ設計上の問題を起こしやすいことや、オーバーライドを許さなければコンパイラのコード生成における最適化がもっと期待できるというようなことが書かれています。
これらを踏まえると、私は次のように使い分けるのがいいと思いました。
- アクセスレベルを特に意識しないプログラム → 何もつけない or
internal - アクセスレベルを意識する場合
- 別のモジュールからも使えるようにしたい →
public- そのうち、継承させたりオーバーライドさせることが前提のもの →
open
- そのうち、継承させたりオーバーライドさせることが前提のもの →
- 実装を他からは隠したい →
private- でも特定のコード間では共有したいとき →
fileprivateにして共有したいコードを同じソースファイルにまとめる(うまくextensionを使うのが良さそうですね)
- でも特定のコード間では共有したいとき →
- それ以外 → 何もつけない or
internal
- 別のモジュールからも使えるようにしたい →
つまり、普段は public, internal, private の3つを使うようにして、特定の意図があるときにのみ open や fileprivate を使うというのがいいんじゃないでしょうか。
新しいキーワードを増やすだけでなく、既存のキーワードの意味を変えてきたことからも、普段は public や private を使えということだろうと思います。
既存コードをXcode 8のコードマイグレーションでSwift 3にマイグレートすると、従来の public は open に、 private は fileprivate に書き換えられてしまいます。しかし、ここは注意して public や private に戻していきたいところです。