Rubyの継承階層の話 - Effective Ruby

『Effective Ruby』を読む。前回の日記は、こちら。

今日は2章を最後まで読みました。復習は、2章の頭からです。

項目6 Rubyが継承階層をどのように組み立てるかを頭に入れよう

クラスもオブジェクトだという話が出てくる。(次の言い回しは面白い)

つまり、クラスは、持っている変数がクラス変数と呼ばれ、持っているメソッドがクラスメソッドと呼ばれるようなオブジェクトである。

また、メソッドの実行中、self変数には、そのメソッドのレシーバが入っている。

この項目で解説されている内容を要約するとこんなかんじ。

モジュールをクラスAでincludeすると、Rubyが特異クラスを作成して、クラスAの1つ上のクラス階層にこっそり追加する。特異クラスは不可視なので、クラスAのスーパークラスを問い合わせても、モジュールをincludeする前と変わらない結果を返す。しかし、メソッドのルックアップでは、こっそり追加された特異クラスをも走査する。

特定のオブジェクト専用のメソッドも、クラスメソッドも、特異クラスと同じ仕組みで実現されている。

要約終わり。面白い。この知識はデバッグする時に役にたつかも。

なお、メソッドが見つからない場合は、最初の場所から今度はmethod_missingメソッドを探す。しかし、method_missingを独自定義してはいけないらしい。理由は項目30までおあずけ。

Effective Ruby

Effective Ruby

項目7 superのふるまいがひと通りではないことに注意しよう

サブクラスと同じ名前のスーパークラスのメソッドをどうやって呼び出すかについて。

superはメソッドではなくキーワードなので、superを呼び出す時のカッコのあるなしで、振る舞いが変わるとのこと。

  • カッコと引数、または引数だけをつけて呼び出し: オーバーライド対象のメソッドにそれらの引数を渡す
  • カッコだけつけて引数なしで呼び出し: オーバーライド対象のメソッドに引数を渡さない
  • 何もつけずに呼び出し: オーバーライド対象のメソッドにオーバーライドしたメソッドに渡された引数をそのまま渡す

3つ目が注意すべきケースで、次のようなことが起きる。

  • 2つのメソッドが同じ個数の引数を取らないと、呼び出し時にArgumentErrorが起きる
  • super呼び出し前にオーバーライドするメソッドで最初の引数を変更すると、変更後の値が渡される

また、オーバーライド対象のメソッドをどうやって見つけるかについて。includeされたモジュールに同じ名前のメソッドがあると、本来のスーパークラスより先にそちらが使われるとのこと。

これ、おそろしいな。自分の知らないところでincludeされたモジュールで、本来のスーパークラスのメソッドが隠されてしまうとか、あるあるなのではないか(想像だけど)。

それから、項目6に出てきた、method_missingを独自定義するなという話が繰り返されてる。デフォルトのmethod_missing実装では、super呼び出し失敗時にNoMethodErrorが得られるが、独自定義すると失われてしまうかららしい。

項目8 サブクラスを呼び出すときにはsuperを呼び出そう

スーパークラスのinitializeメソッド(コンストラクタのようなもの)は自動で呼び出されない、という話。

言い換えると、コンストラクタによる差分プログラミングには、明示的なsuper呼び出しが必要である。なんと! 項目7に出てきたsuperの規則に従うわけだ。initializeメソッドだからといって特別扱いしないのは、覚えるべきことが増えなくていいかも。

あと、新しいオブジェクトをセットアップする方法として、dup、clone、initialize_copyが(名前だけ)出てきた。このあたり知らなかったのであとで調べよう。

今日はここまで。