「『常識』というよりは『理解の基盤』と『説明の方法』」に挙げた4つの問いかけのなかで、
- メソッド内で使える「this って何?」と聞かれたら…。
これはなんか異質でしょう。thisは、僕自身の記憶に残っている例なんだよね。(以下、愚痴口調の文体。)
「犬とポチ」はやめてくれ
僕は、オブジェクト/クラスの概念が全然分からなかったし、今でも分からないよ。「犬クラスは哺乳類クラスのサブクラスで、ポチは犬クラスのインスタンスだ」とか「タイヤは自動車クラスのインスタンスではないが、自動車はタイヤを持つ(HAS-A)のだ」とか。そのテの説明を最初に見てしまったのがいけなかった。
犬とかポチとかは、動物学/分類学/博物学、あるいはペットショップで必要な概念なんじゃないの。それがどうした? という気分。今の僕は、このテの説明を全否定はしない。それで納得した気分になる人がいる事実を知っているからね。大人だね>僕。
その後に、「オブジェクトは実世界の存在物に対応する」とか「クラスは、現実を抽象化すれば得られる」とか、わけわからん御託と能書きに接して、ますますイヤになった。心底嫌いになった。今の僕は、実世界/現実との対応を出すことを全否定はしない。そういう観点と能力が実際に必要/重要であることを知っているからね。大人だね>僕。<シツコイ!
だけどね、計算現象、プログラミング言語機構としてのオブジェクト/クラスを理解できたその後で、実世界・現実との対応を考えてもいいのじゃないのかな。「犬とポチ」を出されても計算現象への認識を深める役には立たないよね。
メッセージというのがまた分からない
今の僕は(またかよ)、メッセージ・パッシングというメタファーは便利だし、役に立つと思っている(ほんとだよ)。でも、なんか擬人化されて、class A
内で発生する呼び出しb.hoge()
を「aさんがbさんに『hoge』という命令や伝言を送ることです」とか言われると鳥肌が立つ(気持ち悪くて)。まー、これは僕固有の感性で、異常体質なのかもしれない。
それで、一番わからないのが、thisとかselfに対するメッセージ・パッシング。「自分にメッセージを送る」って何よ、それ? 他人を動かすならともかく、自分ならサッサとやりゃいいじゃん。イチイチ「俺、お茶飲め」とか「私、ドア開けましょう」とかメッセージしないといけないわけか。
まー、たしかに「がんばるんだ、俺」とか「明日までには必ず終わらせなきゃね、私」と心のなかで思うことはあるだろうけど、たまに。ところで、ゴルゴ13って知っている? 彼は機械のようにクールな奴なんだが、初期の頃、なんと彼は「落ち着くんだ、ゴルゴ」とか自分に言い聞かせちゃっているんだよ。ゴルゴらしくねーー。恥ずかしいなー、ゴルゴ。やーい、若気の至りか、ゴルゴー。
のぞき見で分かったこと
C++の初期の処理系はcfrontというトランスレータで、Cソースを吐くだけだった。で、僕は中間のCソースをのぞき見していた。それでやっと事情が飲み込めたんだよね、僕としては。
Java風の記法に換えて説明すると、obj.someMethod(arg)
という呼び出しは、functionFor_someMethod(thisRef, arg)
のようにトランスレートされる。つまり、参照引数を1つ余分に持った関数(サブルーチン)になるわけね。隠れた引数thisRefは、ヒープ上にあるメモリブロック(構造体だと思ってよい)を指している。
それで、フィールドアクセスthis.field
は、thisRef->field
(thisRefが指しているメモリブロックの特定位置のデータを取得)になるし、メソッド呼び出しthis.foo()
は、最初と同じルールでfunctionFor_foo(thisRef)
となる。
オブジェクトが「ヒープ上に割り当てられたメモリブロックと、いくつかのサブルーチン群を紐付けて一緒に考えたもの」だとして、問題のメモリブロックとサブルーチンを“紐付ける”さいに、サブルーチンにこっそりと渡してあげる引数がthisなのよ。
それって、いくらなんで即物的過ぎないか
以上の説明は、(他でも似たようなことやっているにしても)cfrontとCコンパイラの処理系実装方式に依存した説明であり、理念的な理解とはほど遠い。しかし、こと僕自身に関して言えば、「this(あるいはself)は自分を意味する」とか言われても、「自分」という概念が摩訶不思議だし、「自分を意味する」なんて高尚なコトバにイマジネーションが届かない。まったく分かった気分がしない。
僕のようなベタベタな理解・納得はマズイのかな? -- それも分からない。でもね、隠れた参照引数による実現が必ずしもローレベルだけの話ってわけではない。代数的アプローチによりクラス/オブジェクトを説明できる枠組みのひとつに余代数がある(関連する資料の紹介)。余代数によるメソッドの定式化は、隠れた引数を1つ追加する方法なんだ。
結論は特にない
総括的に何が言いたいのかというと、ウーン、べつにないや。「thisの思い出」かしら。
思い出、って言えば、cfront方式はトランスレータとコンパイラが走るから遅いんだよ。それで、いきなりネイティブコードを吐くコンパイラが登場するわけだが、僕が最初に触ったのはゾルテック。その綴り字が思い出せないの、誰か憶えてる?