いいかげん、VMを動かさないといけないよな。少しでもいいから、一日一回くらいは触るようにしていこう。
thisはどうしようか、という話。selfでもいいけど。
オブジェクト指向っぽい言語では、メソッド中で名前を参照すると、そのメソッドが属するオブジェクトのメンバを参照する。まあ、それはオブジェクト指向の超基本的事項だ。が、しかし、PythonやJavaScriptのように、関数の扱いが柔軟なオブジェクト指向言語では、メソッドを定義したオブジェクトと、メソッドを呼び出すメソッドが一致しなくなる場合があって、「ただのメンバ参照」が、少しだけ面倒な問題になるのだ。
コードで書くと。
// 誰もわからないだろうけどILogScriptで書くよ。 var obj1 = object { var x = 4; function refx() { return x; } }; var obj2 = object { var x = 8; }; obj2.refx = obj1.refx; var func = obj2.refx; puts( obj2.refx() ); // -> ??? puts( func() ); // -> ???
こんな感じの時はどういう結果にすべきなのだろうか、という問題。
ちなみに、JavaScriptだと、
var obj1 = { x: 4, func: function() { return this.x; } }; var obj2 = { x: 8 }; obj2.func = obj1.func; var func = obj2.func; print( obj2.func() ); // -> 8 print( func() ); // -> undefined
こんな感じで、Pythonだと、
class Class1: def __init__(self): self.x = 4 def refx(self): return self.x class Class2: def __init__(self): self.x = 8 obj1 = Class1() obj2 = Class2() obj2.refx = obj1.refx func = obj2.refx print obj2.refx() # -> 4 !! print func() # -> 4
こんな感じ。っていうか、これの結果は4になるのか…
うーん、Pythonの結果がちょっと意外だったので、話が進めにくくなってしまった。"obj.method()"って"method(obj)"のsyntax sugarじゃなかったのね。
まあいいか。とにかく、上の場合だと、どういう結果になるのが自然なんだろうか。
僕が思うに、
puts( obj2.refx() ); // -> 8(obj2.x) puts( func() ); // -> 4(obj1.x)
これが一番自然っぽい感じがするのだけど、どうだろうか。じゃあ、これに、
obj3 = object { var x=512; }; obj3.refx = obj2.refx; func = obj3.refx; puts( func() ); // -> ???
を追加すると、何を表示すべき?4を表示すべきだと思うが。
僕が自然と感じるルールとしては、
- メソッド内で名前参照があった場合は、いまのthisのメンバを参照する。
- obj.method() という形でメソッドが呼ばれた場合は、objをthisとする。
- method() という形でメソッドが呼ばれた場合は、そのメソッドを定義したオブジェクトをthisとする。
といった感じだろうか。
ただし、これをやろうと思うと、関数が、常に「どのオブジェクトに属するか」を覚えとかないといけない。すると、関数オブジェクトが共有できなくて、メモリ消費が多くなる。が、これについては、あの対策で問題無いだろう。対策についてはまた機会があったら書く。
けど、なんだ、ここらへんの話が話題になってるのを見たことが無いので、実際どうなっていようと構わないような話なのかもしれない。ただのひとりごとです。気にしないで。対象読者は自分。