見出し画像

クラスの概念を間違えてるぞ!?

大誤解をされている記事を多く…と言うか殆どが間違えていると思いますが、クラスと継承について説明する時に現実世界のメタファーを利用する事自体が誤っていると言う事を知らないのかが不思議です。現実世界のメタファーを使って説明している書籍や記事は信頼に値しません。(断言!

例えば「トラック」と「バス」クラスを作成する例で考えてみます。それぞれのクラスでは、「残りの燃料」や「走行距離」といった属性(プロパティ)を持っていることや、「走る」「ガソリンを入れる」などの操作(メソッド)は共通しています。このような場合に「継承」が使えます。具体的に言うと、新しく「車」クラスを作成し、その中に共通する属性や操作を書きます。そして、「トラック」と「バス」クラスは「車」クラスの機能を引き継いで作成します。継承元のクラス(今回の場合は「車」クラス)は「スーパークラス」、継承先のクラス(今回の場合は「トラック」と「バス」クラス)は「サブクラス」と呼ばれています。

うん、まぁ何となく判った気になってしまいますよね…でもここでスーパークラスである「車」に問題がある事にお気づきになりますか?では、簡単な実例を挙げてみますね。ここでは恐らく誰でも簡単に判るであろうRuby 2.6.0のArrayクラスについて考察してみましょう。

Arrayクラスの継承リストは“Array < Enumerable < Object < Kernel < BasicObject”となっています。但し、正確に言うと“Kernel”はクラスではなくモジュールです。このモジュールは“Object”クラスにインクルードされているだけですので継承関係はありません。ですから公式にある上記の継承リストでは誤解を招きかねませんね。

class BasicObject
クラスの継承リスト: BasicObject

と定義されていますから、Ruby 2.6.0のルートクラスが“BasicObject”である事が判ります。そして、この“BasicObject”の説明を読むと

インスタンスメソッド
! != == __id__ __send__ equal? instance_eval instance_exec

と言う記述があります。これが意味するところが判りますか?ルートクラスもインスタンス化できると言う事を意味しています。これはとても重要な事ですので、しっかり覚えてくださいね。

ちなみに私が最も得意とするObjective-Cにおけるルートクラスは“NSObject”です。データ型などを扱う”Foundation Framework”や画面表示・操作に使う“UIKit Framework”も含めて、本当の意味でのスーパールートクラスです。Swiftを使っている方も実は裏側は同じクラスを使っています。

おそらく一番判りやすいのは、画面表示にはかかせないUIViewControllerだと思いますので継承関係を示します。“UIViewControllerUIResponder < NSObject”です。ちなみにナビゲーションを行うUINavigationControllerは”UINavigationController < UIViewController < UIResponder < NSObject”です。

Initializing a Class
class func initialize()
Initializes the class before it receives its first message.
class func load()
Invoked whenever a class or category is added to the Objective-C runtime; implement this method to perform class-specific behavior upon loading.
Creating, Copying, and Deallocating Objects
init()
Implemented by subclasses to initialize a new object (the receiver) immediately after memory for it has been allocated.
func copy() -> Any
Returns the object returned by copy(with:)
func mutableCopy() -> Any
Returns the object returned by mutableCopy(with:) where the zone is nil.
Identifying Classes
class func superclass() -> AnyClass?
Returns the class object for the receiver’s superclass.
class func isSubclass(of: AnyClass) -> Bool
Returns a Boolean value that indicates whether the receiving class is a subclass of, or identical to, a given class.

と言うようにNSObjectにもインスタンスメソッドが存在しています。つまり、NSObject(ルートクラス)はインスタンス化できるという事です。

つまり、クラスベースのオブジェクト指向の世界では、その言語系のルートクラスもインスタンス化できるのが一般的です。ここであえて「一般的」と言ったのはマルチパラダイム言語の一部では当てはまらないケースがあるからです。

無理に現実世界のメタファーを使うと破綻する

では、最初の現実世界のメタファーの例に戻って考えてみましょう。車をインスタンス化できる人っているんでしょうか?他にも”生物>動物>犬>小型犬>ポメラニアン”のような説明も多くみかけますがポメラニアン以外をインスタンス化できるはずがありません

「俺はできるぞ!」と言う方、ご連絡くださいませ。

結論として言える事は一つだけです。それはクラス型オブジェクト指向において継承関係を説明するのに現実世界のメタファーを絶対に使ってはならないと言う事です。現実世界のメタファーでは物理的に存在し得ないものをスーパークラスにせざるを得ません。つまり、全く異なる事象を使って他の事象の説明を行っているわけですから、自然科学的に考えても論理的に破綻しています。

オススメ:一度Smalltalkについて簡単にで良いので調べてください。「オブジェクト指向(Object-Oriented)」と言う単語はSmalltalkを形容する為に開発者であるアラン・ケイ博士の考案した造語です


この記事が気に入ったらサポートをしてみませんか?