2008年 05月 13日

Io って頭おかしいなぁ (いい意味で)

curlyBrackets を知った。

Object curlyBrackets := Object getSlot("method")

foo := {
	"aaa" println
}

bar := {a,
	"bbb" println
	a
}

foo

bar(getSlot("foo")) # method は普通に書くと実行されてしまうので getSlot する必要がある。
aaa
bbb
aaa

ちょっと他の言語に近づいた感じ。

もう少し変態的にしてみる

def foo (mes) {
    mes println
}

こういうふうに書けるようにするために def メソッドを定義する

def := {
	name := call message next name
	args := call message next arguments map(i, i name)
	meth := call message next next
	next := meth next

	# cut message chain
	meth setNext(nil)

	# set the method to caller context
	call sender setSlot(name, call sender doMessage(meth))

	# set arguments list
	call sender getSlot(name) setArgumentNames(args)

	# pass to next message
	call message setNext(next)

	# return the method
	call sender getSlot(name)
}
# 引数なしなら仮引数省略可
def hogehoge {
	"hogehoge" println
}

def piyopiyo (mes) {
	mes println
}

# 引数なしなら括弧いらない
hogehoge
hogehoge()

# 引数ありなら括弧必須
piyopiyo("foobar")

Foo := Object clone do (
	def foo (mes) {
		mes println
	}
)

Foo foo("alert")

書いた式がどうコンパイルされたかは (前にも書いたけど) 以下のようすればわかる。

Message fromString("def foo (mes) { mes println }") code println
#=> def foo(mes) curlyBrackets(mes println)

call message は呼びだしもとのメッセージチェイン (def foo(mes) curlyBrackets(mes println)) をさしてる。call message next は今のチェインの次、すなわち foo(mes) curlyBrackets(mes println) で、call message next name で先頭のメッセージの名前がとれる。メッセージを自分でとって doMessage することでメソッドを作って、呼びだしもとのコンテキストにセットする。setNext でメッセージをチェインを切ったり、スキップしたりする。

実際もっと簡単に

def := method(
	ret := Object clone do (
		foo := method(
			self args := call message arguments map(i, i name)
			self
		)

		curlyBrackets := method(
			meth := method() setMessage( call message argAt(0) ) setArgumentNames(args)

			context setSlot("foo", meth)
		)
	)
	ret context := call sender
	ret
)

def foo () {
	"faaa" println
}

foo

とかだと、method_missing 相当がないのでうまくいかない。(これは動くけど、foo 決めうちだからうごいてる)

method_missing に相当するのは forward だった