これがthisです。わたしはselfを持っています。

いいかげん、VMを動かさないといけないよな。少しでもいいから、一日一回くらいは触るようにしていこう。


thisはどうしようか、という話。selfでもいいけど。


オブジェクト指向っぽい言語では、メソッド中で名前を参照すると、そのメソッドが属するオブジェクトのメンバを参照する。まあ、それはオブジェクト指向の超基本的事項だ。が、しかし、PythonJavaScriptのように、関数の扱いが柔軟なオブジェクト指向言語では、メソッドを定義したオブジェクトと、メソッドを呼び出すメソッドが一致しなくなる場合があって、「ただのメンバ参照」が、少しだけ面倒な問題になるのだ。


コードで書くと。

// 誰もわからないだろうけど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とする。

といった感じだろうか。


ただし、これをやろうと思うと、関数が、常に「どのオブジェクトに属するか」を覚えとかないといけない。すると、関数オブジェクトが共有できなくて、メモリ消費が多くなる。が、これについては、あの対策で問題無いだろう。対策についてはまた機会があったら書く。


けど、なんだ、ここらへんの話が話題になってるのを見たことが無いので、実際どうなっていようと構わないような話なのかもしれない。ただのひとりごとです。気にしないで。対象読者は自分。