Hatena::ブログ(Diary)

Smalltalkのtは小文字です

id:sumim:about

Smalltalk を本格的に勉強する気はないけれど、うんちく程度に知っておきたいなら→Smalltalkをちょっとかじってみたい人のための、チュートリアルまとめ - Qiita

オブジェクト指向の“モヤッと”の正体を知りたくなったらこちらの記事が役に立つかも→id:sumim:20080415:p1 とか id:sumim:20040525:p1


 | 

2006-12-01

[][][] サブクラスから自身がオーバーライドしたスーパークラスのメソッドを呼びたいとき


より正確には、サブクラスのインスタンスから、自身が属するクラスがオーバーライドしたスーパークラスのメソッドを、自身が属するクラスに定義した別のメソッドからコールしたいときにはどうするか?…でしょうか。(^_^;)


2chの Ruby 初心者用スレへの投稿 より。具体的には、次の D#bar で B#foo を呼びたいときの対処法について。以前から漠然と、Smalltalk の super と違う Ruby の super の仕様(こういう仕様の言語ってほとんどないですよね。もしや Ruby のオリジナル? 追記:よく似たものに Eiffel の Precursor というのがありました)だと、いろいろと問題があるんじゃないかなぁ…と思っていたところなので、そのよい例としてメモ。


class B
  def foo; "B#foo" end
end

class D<B
  def foo; "D#foo" end
  def bar
    # どうする?
  end
end

Smalltalk では super は self と同様のしかし特殊な振る舞い(メソッド検索だけは、実行中のメソッドの属するクラスのスーパークラスから始める…)をする擬変数なので、このような場合でも普通に super foo と書くことができます。(以下、メタ情報を除いた加工コード(ファイルイン不可。ブラウザへのコピペが必要)にて)


Object subclass: #B

B >> foo
   ^ 'B >> #foo'

B subclass: #D

D >> foo
   ^ 'D >> #foo'

D >> bar
   ^ super foo
D new bar   " => 'B >> #foo' "

一方、Ruby の super は、Smalltalk の super のような擬変数(メッセージレシーバ、あるいは、ドットアクセス演算子の第一オペランドとして使用される…)ではなく、スーパークラスの同名メソッドの エイリアスなので 別名メソッドがごとく(たとえるなら、super という名前に alias した後、private 属性を付したかのように…)振る舞うので、こうしたケースには役に立ちません。そこで、二つの解決策が提示されています。(「エイリアスなので」という表現には語弊があるので緑色部分として書き換え、書き足しました。rubyco さん、ご指摘、痛み入ります。)


エイリアスを用いる alias で別名を作る方法
class D1 < B
  alias :super_foo :foo
  def foo; "D#foo" end
  def bar
    super_foo
  end
end
D1.new.bar   #=> "B#foo"

メソッドオブジェクトを引っこ抜いて直接叩く方法
class D2 < B
  def foo; "D#foo" end
  def bar
    self.class.superclass.instance_method(:foo).bind(self).call
  end
end
D2.new.bar   #=> "B#foo"

前者は D1#foo の定義前に alias しておくというのがミソですね(というか、alias の使用パターン?)。後者は Python や JavaScript チックな発想ですね。Squeak の Smalltalk で無理矢理表現するなら、


D >> bar2
   ^ (self class superclass lookupSelector: #foo) valueWithReceiver: self arguments: #()
D new bar2    " => 'B >> #foo' "

という感じでしょうか。


id:sumim:20061203:p1 へ続く。



ところで、これは先に述べた Smalltalk における super の仕様から、次のように書いてもよさそうに思います。しかし残念ながら、この記述では期待どおりの動作をしません。


D >> bar3
   ^ (super class lookupSelector: #foo) valueWithReceiver: self arguments: #()
D new bar3  " => 'D >> #foo' "

理由は、Squeak のバイトコードインタープリタが、メッセージ「class」を実際には送信していないからです。ちょっとした衝撃の事実ですね(^_^;)。その代わり、この「class」に限っては常にハードコードされたバイトコード(16rC7。インタプリタ内では #bytecodePrimClass)を直接コールすることになっています。同様の理由で、#class はオーバーライドすることもできないので、注意が必要でしょう。こうした例外には #class の他に、#==(バイトコード 16rC6。同、#bytecodePrimEquivalent)があります。

rubycorubyco 2006/12/02 08:44 「Ruby の super はスーパークラスの同名メソッドのエイリアスなので」の部分の典拠はありますか?Ruby本を見たのですが見つかりませんでした…。

sumimsumim 2006/12/02 10:26 Ruby を使って感じた印象なので“典拠”というのは特にありませんが、しいて挙げるなら、青木さんの「Rubyソースコード完全解説」(俗に RHG - Ruby Hacking Guide とも)の題8章 http://tinyurl.com/y837jz と第15章 http://tinyurl.com/yyfcwr 、あと、正誤表 http://tinyurl.com/y2bzss それぞれの super への言及がそれにあたりましょうか。super は擬変数ではなく、メソッド(擬似的な…)として実装されています。それとは別に、ご指摘を受けてあらためて読み返すと“エイリアス”は、Ruby の alias で作った…という意味と、別名(エイリアス)である…という意味で、明示的にせずに使い分けてしまっているようです。前者の意味で受け取っておられたのでしたら当方の書き方が悪かったです。ごめんなさい。書き直します。

sumimsumim 2006/12/02 10:48 追記を読みました。「Rubyソースコード完全解説」にはすでに目を通されたうえでいただいたコメントだったのですね。重ね重ね、失礼いたしました。

rubycorubyco 2006/12/02 11:17 コメント感謝です。『Rubyソースコード完全解説』は読んでいませんでした。『オブジェクト指向スクリプト言語Ruby』のp.174, p.180を読んだのでした。

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト

コメントを書くには、なぞなぞ認証に回答する必要があります。

 | 
2004 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2005 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2006 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2007 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2008 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 12 |
2009 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2010 | 01 | 02 | 03 | 04 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2011 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2012 | 01 | 02 | 03 | 04 | 05 | 06 | 08 | 10 | 12 |
2013 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 11 | 12 |
2014 | 01 | 02 | 05 | 07 | 08 | 09 | 10 | 11 |
2015 | 04 | 07 | 08 | 11 | 12 |
2016 | 02 | 03 | 06 | 07 | 08 |
2017 | 04 | 05 | 06 |

最近のコメント

1. 06/28 sumim
2. 06/28 squeaker
3. 06/28 sumim
4. 06/28 squeaker
5. 06/25 sumim

最近のトラックバック

1. 05/25 プラグインレスでSVGを表示する「SIE」開発ブログ - メッセージをや...
2. 01/30 no_orz_no_life - Erlangとジャンケン
3. 12/31 檜山正幸のキマイラ飼育記 - J言語、だってぇー?
4. 09/04 Twitter / @atsushifx
5. 07/06 みねこあ - オブジェクト指向 と FizzBuzz

この日記のはてなブックマーク数
1776089