0
1

More than 3 years have passed since last update.

superは単に親クラスのメソッドを呼び出すものではない

Last updated at Posted at 2020-11-05

はじめに

ruby gold取得に向けて勉強中superについて自分の中での理解が変わり共有したいと思いました。

本題

まず初めに以下のコードを実行するとどのような結果が出力されるでしょう?


module M
  def foo
    super
    puts "M#foo"
  end
end

class C2
  def foo
    puts "C2#foo"
  end
end

class C < C2
  def foo
    super
    puts "C#foo"
  end
  include M
end

C.new.foo

選択肢1

C2#foo
C#foo

選択肢2

C2#foo
M#foo
C#foo

選択肢3

エラーが表示される

僕はずっと1と思ってました。
ちなみに正解は 選択肢2
きちんと理解して正解した方はもうこれ以上見なくて大丈夫です。
ここまで見てくださってありがとうございます。

まず、僕がどのようにして選択肢1を選んだのか

「Cクラスのfooメソッドやな、ふむふむ」
「お、superか。てことは親クラスのfooを見ればいいんやな」
「なるほど、答えは1や!」

こんな感じです。
モジュールをincludeしたところで呼ばれないと思っていました。

superクラスについて学んでいきましょう。
まず初めにリファレンスマニュアルに書いてあるsuperについて簡単に

super は現在のメソッドがオーバーライドしているメソッドを呼び出します

なるほど、スーパークラスのメソッドを呼び出すわけではなさそうです。
ではancestorsメソッドを使用してみます。

## 省略

class C < C2
  def foo
    super
    puts "C#foo"
  end
  include M
  self.ancestors #=> [C, M, C2, Object, Kernel, BasicObject]
end

C.new.foo

ancestorsは簡単に説明するとメソッドの探索順位がわかるメソッドです。
例えばfooメソッドを実行した時Cのfooメソッドを探し、なければMのfoo...と探索していきます。

ここでもう一度問題のコードを見ていきます。

module M
  def foo
    super # C2のfooを参照する
    puts "M#foo"
  end
end

class C2
  def foo
    puts "C2#foo"
  end
end

class C < C2
  def foo
    super # Mのfooを参照する
    puts "C#foo"
  end
  include M
  self.ancestors #=> [C, M, C2, Object, Kernel, BasicObject]
end

C.new.foo
#=> C2#foo
#=> M#foo
#=> C#foo

結論

  • superの記述があると次のメソッドの探索が行われる
  • 親クラスのメソッドを探索するわけではない

おわりに

資格勉強していると結構理解が深まるので実務経験が浅い方は勉強してみてもいいのではないでしょうか?

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1