Swift 4+ の文法における `open` キーワードについて理解する
アクセス修飾子 (Access Modifier)
プログラミング言語、例えばJavaを例にとると、public, private, protected は、フィールド、関数、クラスへのアクセス範囲を制御するために使用されます。final, open, override, abstract のような継承関連のキーワードも「アクセス修飾子」の範疇に含まれます。(アクセス修飾子は可視性修飾子 (Visibility Modifier) と呼ばれることもあります)
脆弱な基底クラス (Fragile Base Class)
脆弱な基底クラス問題は、継承によって発生する問題で、基底クラスとそれを継承するサブクラスがある場合、基底クラスの変更が発生するとサブクラスが壊れる問題を意味します。基底クラスをサブクラスが継承する際に、どのメソッドをどのようにオーバーライドするかについての規則が明示されていないと、サブクラスは意図と異なる方法で任意のメソッドをオーバーライドすることができます。また、基底クラスのメソッドの目的が変更された場合、サブクラスのオーバーライドメソッドは既存の意図と予期せぬ形で異なってしまうため、基底クラスの変更はそれを継承するすべてのサブクラスに影響を与えます。これを基底クラスが脆弱であるという意味で、脆弱な基底クラスと呼びます。
初期のオブジェクト指向プログラミング言語に該当するJava、C#、C++の場合、オブジェクト指向の特徴である継承が容易になるように、アクセス修飾子を特に明示しない限り、すべての基本クラスは継承が可能です。しかし、脆弱な基底クラス問題を防止するため、『Effective Java』の著者も「継承のための設計と文書を用意するか、それができないなら継承を禁止せよ」と述べているように、すべての基本クラスは継承しないことをソフトウェアアーキテクチャおよびデザインパターンで推奨しています。
初期のオブジェクト指向プログラミングを使用する中で発見された限界や問題は、言語を継続的にアップデートすることで補完されることもありますが、新しい言語はこれらの良いパターンを自分たちの特徴として取り入れることもあります。現代のオブジェクト指向プログラミング言語であるKotlinとSwiftがその一つです。冗談めかしてこのような言語を「チャンポン」(様々な要素が混ざり合っている、ごちゃ混ぜ)と呼ぶこともありますが、それだけパターンを文法として強制する利点を持っています。
Swift, Kotlin では Java と異なりデフォルトで継承不可
Java は脆弱な基底クラス問題を持つ初期のプログラミング言語として、デフォルトですべての基本クラスは継承が可能です。Kotlin と Swift は、この問題解決のためにデフォルトですべての基本クラスを継承不可(final)にしています。したがって、Swift の2つのタイプである class と struct はどちらもデフォルトで継承不可です。
さらに、Java の変数、クラス、関数はすべて、デフォルトで何もアクセス修飾子を明示しなければ package-private で宣言されますが、Kotlin と Swift の場合、何もアクセス修飾子を明示しなければ public で宣言され、どこからでも使用できます。そして public はデフォルトで final であり、継承は不可能です。
- public = 継承不可 + 呼び出し可能
- open = 継承可能 + 呼び出し可能
open class User {
open func login() { }
public func playGame() { }
public init() { }
}
Kotlin、Swift ともに、継承を行うためにはクラス、関数、変数すべてに open キーワードを追加する必要があります。関数と変数に open キーワードを使用することで、クラス全体レベルではなく、関数、変数レベルで「継承可能なもの」と「継承不可能なもの」を容易に管理できるという利点があります。
これまで見てきたように、JavaとKotlin、Swiftの継承に対する扱いは完全に逆です。public なクラスや関数をデフォルトで継承可能にし、継承を制限するために private や protected のようなアクセス修飾子を使用するJavaとは異なり、Kotlin、Swift は開発者に対してデフォルトで全て継承不可能にした上で、そこから追加で継承を行うためには open を明示するように制限することで、誤った継承を防ぎます。そのため、Swift で open を使用していると、関数、変数単位での継承の可否を決定するため、Java の abstract と似たような感覚を受けることがあります。