幸ログ

ナレッジを溜めていきます

Ruby Goldを目指して ~ Mix-in 1 ~

include prepend extend

Mix-inとは

オブジェクト指向プログラミング言語において、サブクラスによって継承されることにより機能を提供し、単体で動作することを意図しないクラスである。*1
単体で動作することを意図しないクラスとはインスタンスが生成されないクラスのことでです。
無名クラスと言われます。 RubyでいうとModuleに当ります。 (他の言語は存じてない!)
インスタンスを生成されないクラスをどうやって使うのかというとMix-inという仕組みを使うことで使用可能になります。
今回はinclude prepend extendの3つを説明していきます。

includeとは

includeとはインスタンスの生成が可能なクラスを拡張するものです。
includeの継承では継承の対象となるクラスの親の位置に定義されます。 includeでModuleを追加することで拡張の効果が見られます。

includeの説明

prependとは

includeと同じく、prependとはインスタンスの生成が可能なクラスを拡張するものです。 挙動はincludeと違う動きをします。 includeの継承では継承の対象となるクラスの親の位置に定義されるに対して、prependは子の位置に定義されます。

prependの説明

includeとprependを使う時の気を付ける点

この二つはMix-inをするために準備されています。
じゃぁどっちを使ってもいいんですね!ということにはなりません。
この二つを使う時に気をつける点はメソッドの探索に目をつける必要があります。

メソッド探索とは

メソッド探索とは継承されているクラスに対して呼び出されたメソッドを子から親へ順番に探し、実行するものです。
メソッドが存在しない場合は例外が発生します。
さて、メソッド探索を意識してincludeとprependを使った場合の例を見てみましょう。

includeとprependを使ったメソッド探索

M1はincludeでMix-inされ、M2はprependによりMix-inされています。 それではインスタンスから#hogeを呼び出された時はどのModuleの#hogeが呼び出されたでしょうか?
答えはM2の#hogeが呼び出されています。
理由としてはメソッド探索の説明に書いえある「子から親へ順番に探し」が鍵となっています。
メソッド探索は子から親へと順番に探し、見つけたメソッドを実行して探索は終了します。 この場合prependされているM2が先に#hogeが発見され実行し探索は終了しています。 このようにincludeとprependを意識をせずに使うことで、M1の#hogeを呼び出そうとしているはずがM2の#hogeが呼び出されるという問題が起こってしまいます。
includeとprependは継承のされ方を意識して定義をすることが大切です。

expendとは

expendとはinclude、 prependにようにインスタンスメソッドをMix-inするのではなく、特異メソッド(クラスメソッド)をMix-inするものです。

#特異メソッド(クラスメソッド)とは

特異メソッド(クラスメソッド)とはインスタンスから呼び出すメソッドではなく、クラスから呼び出されるメソッドです。
詳しくはレシーバーについて調べると理解が深まります。
それでは本題へ。

extendの説明

Moduleを使っての特異メソッド(クラスメソッド)の定義が可能になります。
extendを使用した際の継承は追加されません。

今回はMix-in1ということで次回はMix-in2になると思います。 Refinementの話とかになりそうですね。

マサカリ待ってます!