だいたい必要なのはある
メッセージングは OOP での一番重要なとこ
// foobar を表示する Io のコード "foobar" println
// JS っぽい疑似コード "foobar".alert();
他の言語だとドットやアローがあるところはスペースになっている
list("a", "b", "c") at(0) #=> "a"
list("a", "b", "c") println
引数を渡したいときは括弧が必須
引数をとらないメソッドは括弧を省略可
# foo に新しい手続きを代入
foo := method("foo called" println)
foo("not shown" println)
# foo callled のみ表示される
重要:引数は基本的には全く評価されない
全部ブロック渡し・関数渡しみたいなもの
# method 定義時に仮引数 arg を書く
foo := method(arg, arg println)
foo("shown" println)
# shown が二回表示される
仮引数 (arg) を書けば自動的にそれは評価される
# 明示的に引数を eval する
foo := method( call evalArgAt(0) println )
foo("shown" println)
# shown が二回表示される
call というスロットは特別重要
制御構文の例を if で
if (a > 1) then ( "foo" println ) else ( "bar" println )
実はメソッドチェイン
if(a > 1).then(function () {
alert("foo");
}).else(function () {
alert("bar");
})
(a > 1) ifTrue( "true" println)
単にメソッドを呼んでるにすぎない
false は ifTrue の引数を評価しない。true ならする、の違いで分岐する
class TrueClass; def ifTrue(&block) block.call end end
class FalseClass; def ifTrue(&block) end end
true.ifTrue { p "true" }
(a > 1).ifTrue { p "true" }
if (a > 1, "true", "false")
一番高速、返り値が評価したメッセージの値になる
たぶん一番よく使う。ちょっと読みにくい。
Message オブジェクト
// 普通な感じ list(1, 2, 3) map(i, i * i) #=> list(1, 4, 9) // ちょっと特殊 (部分適用のように見える) list(1, 2, 3) map(*3) #=> list(3, 6, 9)
List mymap := method(
m := call message argAt(0);
map(i, i doMessage(m))
)
list(1, 2, 3) mymap(println)
list(1, 2, 3) mymap(*(3))
対象オブジェクトに引数にあたえられたメッセージを送っている
# foo := method(mes, "foo #{mes}" interpolate println )
def foo (mes) {
"foo #{mes}" interpolate println
}
# ↑ もはや Io に見えない。def が function ならまんま JS
パーサーの挙動を変える
Io はパーサの挙動を一部変えれます。
Message fromString(""" "abc" =~ "a." """) code print
#=> "abc" =~ "a."
OperatorTable addOperator("=~", 7)
Message fromString(""" "abc" =~ "a." """) code print
#=> "abc" =~("a.")
# ↑ "a." が =~ の引数になっている
非同期
foo := method(wait(3); 1) a := foo #=> 3 秒まって1 a := @foo #=> 即座に Future オブジェクトが返る a #=> ここで 3 秒まつ a #=> もう待たないで即座に 1 が返る
非同期指定されたメッセージはキューに入る。
a := @foo #=> 即座に Future オブジェクトが返る yield; yield; yield #=> 他のコルーチンに処理をゆずる a #=> 即座に 1 が返る
以下若干細かいところ
o := Object clone o forward := method( call message name println ) o foobar #=> foobar が表示される
foo := method( "foobar" println ) foo #=> 呼び出しされる bar := block( "foobar" println ) bar call #=> call が必要
あとは self の違い
a := Object clone
a foo := method( self )
(a foo == a) println #=> true
b := Object clone
b foo := a getSlot("foo")
(b foo == b) println #=> true
# method の self は呼びだし時に決定するレシーバ
b := block( (self == Lobby) println #=> true ) b call #=> Lobby は JS でいうところの window (Lobby Lobby == Lobby) # block の self は外側のローカル変数オブジェクトと同じ
That's all! Thank you.