Io の継承モデル
Io の言語として一番面白い部分の一つだと思います。
前提知識として、インスタンスメソッドとインスタンス変数とクラスメソッドとクラス変数の違いはありません、それらは全てスロットと呼ばれます。メソッド呼び出しとクラス変数参照はメッセージと呼ばれます。
Account = Object clone Account init = method(self balance = 0) Account deposit = method(v, balance += v) Account show = method( write("Account balance: $", balance, "\n") )
などという Account をベースクラスとして入金した金に倍率をかけて貯蓄するイカサマ貯金を実現したいとします。
CheatAccount = Account clone CheatAccount init = method( parent = Account ) CheatAccount deposit = method(v, balance += v * 2) myAccount = CheatAccount clone myAccount show myAccount deposit(10) myAccount show
これが解決一つ目。つまるところ親クラスのインスタンスを作ってその後適当にスロットを書き換えちまえば継承になるのです。
CheatAccount2 = Object clone CheatAccount2 parent = Account CheatAccount2 deposit = method(v, balance += v * 3) myAccount = CheatAccount2 clone myAccount show myAccount deposit(10) myAccount show
これが解決二つ目。Io ではベースクラスを検索して解決できなかったメッセージは特殊な変数 parent に対して送られます。よって、前者の継承が後者の継承より優先度の高い継承となります。
まあ、このへんの知識を前提として…
Io で Mixin
私は継承モデルに関しては Ruby の解決が今のところ一番好みです。単一継承 + Mixin。まあ別に私は多重継承で困ったことは無いので C++ でも良いんですけど。
さて、Io の継承構造だと二つまでは簡単だけど三つも四つも Mixin したいときにややこしいなあ…と思いました。で、ちょっと考えたらこの機能を簡単にライブラリ化できるこに気付き、ああいい機構だなあと感心しました。こんな感じ。
# mixiner.io # define Mixiner Mixiner = Object clone Mixiner classes = List clone Mixiner add = method(Class, classes add(Class) ) Mixiner mixed = method( now = Object clone classes foreach(i, Class, next = Object clone next parent = Class clone next parent parent = now now = next ) now ) # using Mixiner A = Object clone A func = method( "A.func\n" print ) A funcA = method( "funcA\n" print ) B = Object clone B func = method( "B.func\n" print ) B funcB = method( "funcB\n" print ) C = Object clone C func = method( "C.func\n" print ) C funcC = method( "funcC\n" print ) C funcCD = method( "C.funcCD\n" print ) D = Object clone D funcCD = method( "D.funcCD\n" print ) # D から継承 ABCD = D clone # A, B, C を Mix するよ abcMixiner = Mixiner clone abcMixiner add(A) abcMixiner add(B) abcMixiner add(C) ABCD parent = abcMixiner mixed # D が直系の継承で A, B, C は Mixin # 優先順位は D, C, B, A のはず abcd = ABCD clone # funcA は A にしか無い abcd funcA # funcB は B にしか無い abcd funcB # funcC は C にしか無い abcd funcC # func は A, B, C にあるので C が優先 abcd func # funcCD は C, D にあるので D が優先 abcd funcCD # おまけ。親を付け変える # よって D が直系、A が傍系 abcd parent = A # func は A しか無い abcd func
まあ、variable arguments を使えばもっと短く書けるでしょうけど、とりあえずわかりやすく書いてみました。
あと言語機能は Concurrency がそれなりのサイズがあって、それと Preset Locals, Introspection (要は Reflection) なんかの細々とした便利機能を覚えればだいたい終わり…なのかな。あと例外か。
Io と Lua
最近比較話が出ているみたいなので。 (http://pc2.2ch.net/test/read.cgi/tech/1063711237/136-)
速度なんかは正直私的にはどうでも良いです。遅くなければ。
私は Lua は C とのインターフェイスがいけてないと思うのです。何が悪いって、スタックを使って情報をやりとりする、ってことはもちろんわかるのですけど、そのスタックをどういうふうに使っているか、そのドキュメントが圧倒的に足りない…と思います。
Lua 内で Lua を操作する時はスタックなんて意識しないのに、C から触る時はやたらと考えなきゃいけないのが愉快じゃない、というか色々ハマったので辛かった。
その点 Io は前回やったような slot 呼び出し/登録 の仕方さえわかってしまえば後は Io の流儀通りに C から操作してしまえば良いんじゃないかな…と思うのです。本当にそうかどうかは調査が足りてませんけど。
プロトタイプベースな言語を一つ見てみたかったから、というのもあるんですけどね。
testsprite for ObjectiveC など
ごにいさんのお仕事 (http://gonypage.ddo.jp/diary/20031208.html#p04) に追従 (http://shinh.skr.jp/misc/index.html?2003052801#2003052801) 。
この頃の記述を見るに私は Lua 始めて半年で次を探してますか…別に Lua を極めたわけでは全然無いですし、というよりむしろ何も知らんのですけどね。
gj == good job だと知る。わーいほめてもらたー。
boost memo (http://shinh.skr.jp/boost/memo/) しばらく休みます。永遠に休むかもしれず。