継承とselfに首をかしげる

変なところで引っかかってしまった。

# Ruby
class C
  def print
    p self.class
  end
end

class C1 < C; end

C1.new.print #=> C1

てっきり出力されるのはCだと思ってた。

selfについて、『初めてのRuby』より

「現在の」オブジェクトを表します。C++JavaC#などにおけるthisに似ています。
(中略)
インスタンスメソッドの中ではそのオブジェクトがselfです。

なるほど、そのオブジェクト自体を指したい時に使う予約語であると。C1インスタンスのメソッドを呼んだのだから、selfもまたC1のインスタンスになる。

理屈は分かったけど、不思議な感じだ。レキシカルに見ると、selfはどうしてもCを指すように思える。

親クラスを書いた時点で、実装者はselfが親クラスであると仮定しているだろう。ところが継承が絡むとその前提が崩れてしまう。もちろんリスコフの置換原則が守られている限りにおいては、子クラスのインスタンスは少なくとも親クラスと同等の挙動をするはずだから、問題は起きないはず。しかし子が親クラスのメソッドをシャドウするようなケースでは整合性を保つのが大変かもしれない。

特にRubyでは、JavaC#で見られるようなabstractやoverrideのように、処理系側で整合性の検証を支援する機構があんまり無いようだ。プログラマが責任もって挙動を保証してやらねばならないっぽい。わぁ大変。まず親の実装を知ってないと。

継承は使いこなすのが難しいと言われる理由が分かる気がする。強力なかわりに、複雑な問題を持ち込んでしまう。

いっそ(実装)継承は無しで?

実装継承を省いて、ぜんぶインタフェース継承と委譲だったら単純化できて楽なのかも……だいぶ昔にゴスリングがそんな事を言ったことがあったらしい。

During the memorable Q&A session, someone asked him: "If you could do Java over again, what would you change?" "I'd leave out classes," he replied. After the laughter died down, he explained that the real problem wasn't classes per se, but rather implementation inheritance (the extends relationship). Interface inheritance (the implements relationship) is preferable. You should avoid implementation inheritance whenever possible

http://www.cincomsmalltalk.com/blog/blogView?showComments=true&entry=3237655868

Google謹製だとかで話題のNoop言語も実装継承を廃する気らしい。

Noop says No to

  • Any statics whatsoever
  • Implementation inheritance (subclassing)
  • Primitive types (everything's an object)
  • Unnecessary boilerplate code
http://code.google.com/p/noop/