せかいや

いまいるここを、おもしろく http://sekai-in-the-box.appspot.com/

【Ruby】include extend の考え方の違いって?

以前、
何でModuleモジュールのプライベートメソッドが任意のクラスで見えるか
は分かったけれど、

どうしてinclude extend 二通りの継承方法があるのか

がまだ分からない。

「そういうものだから」といわれたらそれまでだけど
わざわざextend というルールを採用した理由は?
そこにはどんな思想があるのか。
調べてみよう。

include,extend の違い

前に理解したのは、
include インスタンスメソッドとして取り込む
extend クラスメソッドとして取り込む

このレベルまで。


でも考えてみたら、
Moduleでもクラスメソッドを定義できるし
module_function メソッドも存在する。

いろんな機能がごっちゃになって整理できていない。
順に追ってみよう。

extendはオブジェクトへの追加

公式ガイドをみてみると

Module#include は、
クラス(のインスタンス)に機能を追加しますが、
extend は、ある特定のオブジェクトだけに
モジュールの機能を追加 したいときに使用します。

ふむ。

 

extend(*modules)
引数で指定したモジュールのインスタンスメソッドを
 self の特異 メソッドとして追加します。
module Foo
  def a
    'ok Foo'
  end
end
obj = Object.new
obj.extend Foo
p obj.a #=> "ok Foo"

なるほど。
あくまでもレシーバとなるオブジェクトに性質を注入している。

クラスの地の文も、ただの文だから、
通常のこの書き方は↓

class Aaa
  extend Momo
end

レシーバを略さずに書くと↓

class Aaa
  self.extend Momo
end

つまり、Aaaクラスオブジェクトに性質を注入している。

なるほど。
だからextendで取り込んだモジュールのメソッドは
クラスメソッドになるんだ。

Aaaクラスオブジェクトは
Aaaメタクラスインスタンスであると捉えると、
Aaaクラスへのextendは、
Aaaメタクラスに対する Module#includeと言い替えることもできる。

 

クラスに対してはincludeを使う
オブジェクトに対してはextendを使う

これがお勧めの使い方のようだ。

考え方が違うから、この2種類が存在するのか。
なるほど。