[PR] この広告は3ヶ月以上更新がないため表示されています。
ホームページを更新後24時間以内に表示されなくなります。
すべてがオブジェクト、式は、文ではなく、すべてがメッセージで構成されている。 スロットとは何ですか? slot―【名】【C】自販機等の料金差し入れ口. 何かを差し込んだりする場所や位置のこと。 Iolanguageのスロットは「何かを差し込んだりする場所や位置のこと」という意味が近い。家にある郵便受けのようなもの?(▼クリックで続きを読む)
※公式ガイドでは、iolanguageの文法は、BNF記法で書かれています。 【式の構造】 語 − 句 − 節 − 文 (日本語の場合) 修飾語 +引数節 − 指示節 − 式(文) ≠ 構文 symbol [arguments] − message − expression ≠ statement (Iolanguageの場合)symbol は以下の3つに分類される。 identifer 識別子 = ユーザ/システムが作成した、機能を表す語( 変数名、メソッド名、オブジェクト名等 ) number 数詞 = 数 string 文字列 = 文字 Operator 演算子 +-*/ Comment コメント
expression (exp)【構成要素】
式、Iolanguageにおける最も大きな構造。 { message | terminator } 式は、メッセージ(messages) と、区切り(terminator)から構成される。 ひとつの式は、terminator つまり「 ; 」 または 改行 「\n」で終わる(区切られる) ようになっている。 セミコロン「;」で区切った場合、一行に何個も式を書ける。 改行で区切れば、何行でも式を書ける。メッセージ;メッセージ;メッセージ メッセージ メッセージmessage【構成要素】
メッセージ 、指示節 Iolanguageは、変数も何もかも、すべてメッセージでできています。 メッセージは、シンボル(symbol) と 引数(arguments)から構成されています。、 symbol [arguments] 引数あり → メソッドか何か ユーザー作成メソッド、またはシステム予約済みメソッド(for , while, if 等)を実行している 引数なし → 変数かなにか ユーザーが作った変数、またはシステム予約済みのメソッド(println, exit等)を実行しているprintln ← 引数がない例 for( i , 1 , 10 , i println )← 引数がある例 a := if( a ==1 , c+1 )println や for 、if がシンボルに相当、その隣の括弧()でくくられた部分が引数です。 引数については、欠点もあります、長くなるのでここでは割愛します。 ※見分け方arguments【構成要素】引数
引数は、メソッドに渡すパラメータを記述可能なリストで、小括弧()でくくられています。 変数や条件や戻り値、あらゆるものを、区別なく内包できます。 "(" [exp [ { "," exp } ]] ")" exp つまり「式」をいくらでも内包できます。式は カンマ「,」によって区切られます。if( a ==1 , c+1 )この欠点は、どれが条件なのか、何が内容なのか、見分けがつかないことです。 コメントをつけるか、改行やインデントで読みやすく整形するしかありません。 特に、制御構文のようなことを記述しようとすると、 括弧の入れ子状態になります。 Iolanguageには構文(statement)は存在しないので、 改行やインデントによって構造を表現しなければいけません。 ※JavaScriptや C言語のように、内容を定義する 中括弧 { } がありません。 Iolanguageでは、なにもかも 全てひっくるめて括弧( ) でくくられます。
【その他】各オブジェクトのスロットのAPIに依りますI。 Image , Sound , Color, Object 等のオブジェクトを作る場合 CloneCairo_draw := Object cloneFile , Path, Directory URL の場所(ファイルバス)を表す場合は withPath with(System launchPath, "images/lotus.png")初期化方法はAPIによって違うsurface := ImageSurface create(FORMAT_ARGB32, 256, 256)
【オブジェクトの状態】 slot の状態を調べる
【method とblockの違い】 Io における method と block の違い に書いてあった事を試したら本当だった。とても参考になった。Io> animal := Object clone ==> Object_0x544dc0: Io> animal dog := block("called block baw-baw ");animal cat := method("called method mew-mew"); Io> animal cat Io> animal dog call
【式の送り方】 sender と receiver を理解する。 (非同期メッセージ) sender を表示する方法。forward := method( write("sender = ", call sender, "\n") write("message name = ", call message name, "\n") args := call message argsEvaluatedIn(call sender) args foreach(i, v, write("arg", i, " = ", v, "\n") ) )
【methodの戻り値】Io> a := method( /*身長 : */ a , /*体重: */ b , a+b "aaaaa" // <---- 最後に書いた、この行のメッセージが戻り値になる。 ) Io> a(10,11) ==> aaaaa Io>
【しょうもない実験】Io> dog := Object/*の*/clone/*です*/ ==> Object_0x5be190: dog/*とは*/:= Object/* に */clone/* というメッセージを送った結果である */ Io> a := method(/* arg1 */a,/*arg2*/b,a+b) ==> method(a, b, a + b Io> a := method( /*身長 : */ a , /*体重: */ b ,a+b) ==> method(a, b, a + bIo> dog := method("bawww") Io> (3+8) dog ==> bawwwIo> cat := method("mewww") Io> dog := method("bawww") Io> dog cat ==> mewww Io> write(dog,cat,"\n" ) bawwwmewww ==> nil
いきなりですが終了してみましょうusr$ io Io 20080120 Io>
exit と打ち込むと。Ioの対話モードが終了し、 無事にターミナルの元の画面に戻るようです。Io>exit usr$
出来る限り、表示されるもの全てを調べたいと思います。基本的に同じパターンです。
何か変数やメソッドを追加する → slotSummary メソッドを使って、スロットの状態を確認する。
あらためて、対話モードでioを起動これは何も変数やメソッドがなにも定義されておらず、実行されてない状態です。usr$ io Io 20080120 Io> 別のモードで言い換えると、何も命令が書かれてない Io言語のプログラム ファイルを実行した時も同じ状態ということになります。 このとき、Ioがどのような状態になっているのかを調べるために、 中身を覗いて見てみましょう と打ち込むと、オブジェクトの中身を調べられます。Io> slotSummary |
するとIoから結果が返ってきました。 なんらかのリストが表示されてます。 公式ドキュメントによると、オブジェクトは スロットとProtos というリストから出来ていると書かれている。 確かに、Lobby とか、 Protos、exit といった名前が、スロットとしてリストされてますね これから、上のリストが何を表すのか一緒に調べていきましょう。Io> slotSummary ==> Object_0x50c5b0: Lobby = Object_0x50c5b0 Protos = Object_0x50c0c0 exit = method(...) forward = method(...) Object って何だろう? → 今slotSummary で見てるもの。 Object_0x50c5b0 が今実行中の、一番大元(おおもと)にあるオブジェクト名。 たぶん0x50c5b0というのは、このオブジェクトのある「場所」だと思われる。 また、スロットは、名前(キー) と 値 から構成されるデータで、値は オブジェクト、メソッド、数字、文字など なんでも表すことが出来るそうです。 Lobbyって何だろう? さっきのことを踏まえれば、Lobby の値である中身は Object_0x50c5b0。 これは オブジェクト自身を指している…ということになります。 これが何を意味するのかは置いといて、次にいってみましょう。 Protosって何だろう? なんでしょう??? また 、最初から作り付けの exit や foward というメソッドも、あるなぁということも分かります。 = method(...) というのは 種類を表しているので、実際どんな効果があるのかは 使ってみるしかありません。さて、次にいってみましょう。 exit って何だろう? 一番最初に対話モードでexitと打つと終了していたことに気がつきましたか? exit というメソッドは、まさにこのことだったのです!Io>exit usr$ ということは、対話モードで スロットにある名前、例えば、「Protos」 と打てば、スロットに登録してあるProtos オブジェクトの内容を表示したりメソッドを 実行できるんじゃないでしょうか 再び・Protosって何だろう? さっき気がついたことを元に、やってみましょう なるほど、中にはAddon とか、Core が入っていることがわかります。Io> Protos ==> Object_0x50c0c0: Addons = Object_0x50c820 Core = Object_0x50c580 Coreは実行の中枢にかかわるものが入っている。そして おそらく拡張機能を宣言した場合、Addonに専用メソッドなんから追加されるんでしょうね。 Addons の中身を見てみましょう。このオブジェクトは Protosオブジェクト の中にあったので、中身を見るには Protos Addons と打てば見れます。 普通に Addons と入れても見れますね。Io> Protos Addons ==> Object_0x50c820: EditLine = Object_0x574220 ReadLine = Object_0x111cc20 Io> Addons ==> Object_0x50c820: EditLine = Object_0x574220 ReadLine = Object_0x111cc20 入っているAddon は EditLine と ReadLine 。 exit の件といい、これも辻褄がつきます。 EditLine は 対話モードにおいて、 Io> に入れるコマンドを入力したり編集する機能を提供。 ReadLineは 対話モードにおいて、 入れたコマンドを解釈する機能を提供。 と予想できます。 ちなみに、対話モード中に、矢印カーソルの上キーを押すことで、過去に打ち込んだコマンド履歴をたぐり寄せることが出来ます。 おそらくこの機能もAddonによって提供しているのかな?さて、次ぎにいきましょう。 forwardって何だろう? メソッドを実行しても 反応がないです、 これはまた後で調べてみましょう。 |
Io> slotNames ==> list("forward", "exit", "Responder", "View", "Protos", "app", "OSWindow", "Lobby", "GLObject", "Application")
何か作るたびにスロットに追加されます。
次に、変数を作ってみましょうと打ち込んで、再び slotSummaryしてみる。Io> a := 100 と打ち込むと、オブジェクトの中身がどうなっているかを調べられます。Io> slotSummary ( := はスロットの作成と同時に値を入れてしまいます もし、スロットだけ用意したければnewSlot("a") と書いてください。 このときは内容は nilになります。 また、それをフォローするsetAというメソッドも自動的に用意されます。) |
slotSummaryを使って今の状態を調べます このとき、Io 内部ではどうなってるか? スロットに a という オブジェクト(プロパティ)が 差し入れられたことがわかります。Io> slotSummary ==> Lobby = Object_0x50c5b0 Protos = Object_0x50c0c0 a = 100 <------------------こいつに注目。 exit = method(...) forward = method(...) a には 100 という値を入れたので、値は100となっています 値を見るにはどうすればいいでしょう? |
変数や、オブジェクト、メソッド等も同じやり方
さきほど作った変数 a を呼び出してみよう。Io> a Iolanguageではオブジェクトや値、メソッド等は、単独、もしくは(それぞれスペースで区切られた)複数の「メッセージ」という単位で表されます。 これらは途中セミコロン「;」や改行で区切られない限りは、ひとつのグループとして処理されます。 例えばa というのは、aそのものを表示せよという、メッセージです。 スペースで区切られた場合、 a println; のように。メッセージは左「a」から右へ「println」へ、連鎖するように受け渡されます。 |
結果このように、プログラムへ変数やメソッドを書けば書くだけ 変数やメソッドといった オブジェクトが スロットへどんどん追加、 されていくと予想がつきます。Io> a ==> 100 また、スロットにあるオブジェクトa を呼び出す場合、 a と書けば 100が返ってくることが分かります。 これはメソッドでも同じで、プログラム中にメソッドを書けば、 スロットのほうにメソッドを追加されます。 例えばexit と書く (exit メソッドを呼び出す)と、どうなるでしょう? |
o> Obj := Object clone ==> Obj_0x1123b50: type = "Obj" Io> Obj a ::= 1 ==> 1 Io> Obj b := 2 ==> 2 Io> Obj c = 3 Exception: Slot c not found. Must define slot using := operator before updating. --------- message 'updateSlot' in 'Command Line' on line 1 Io> Obj a = 3 ==> 3 Io> Obj a = 1 ==> 1 Io> Io> Obj ==> Obj_0x1123b50: a = 1 b = 2 setA = method(...) type = "Obj" Io> Io> Obj setB(5) ==> Obj_0x1123b50: a = 5 b = 2 setA = method(...) type = "Obj" Io> |
「::=」 「 :=」 「 =」 の違い。
|
クローンは Lobby オブジェクト に追加される
オブジェクトのクローン(複製)を作ってみよう dog というオブジェクトを作ってみましょう。(※"Dog"の場合はどうなるかな?) slotSummary を使ってObjectの状態を確認Io> dog := Object clone ==> Object_0x5bbf40: Io> slotSummary |
slotSummaryを使って今の状態を調べます あたらに、dog というオブジェクトが追加されました。 クローン元とどういう関係なのか調べてみる?Io> slotSummary ==> Object_0x50c5b0: Lobby = Object_0x50c5b0 Protos = Object_0x50c0c0 a = 100 dog = Object_0x111a5c0 <----こいつに注目 exit = method(...) forward = method(...) dog というオブジェクト、今あるObject のクローン。 その証拠に、dogから a を呼び出すことができます。 Io> dog a ==> 5 |
上の例は、Object型、下の例は Aaa型のオブジェクトである事が分かります。Io> aaa := Object clone ==> Object_0x5e0f30: Io> Aaa := Object clone ==> Aaa_0x1115ad0: type = "Aaa" Io>
Huzzarh!! と表示されるのは、Aaa が作成された時ではなく、 d が作成されたとき。Io> Aaa := Object clone do( init := method("Huzzaaah!!" print) ) ==> Aaa_0x1146970: init = method(...) type = "Aaa" Io> d := Aaa clone Huzzaaah!!==> Aaa_0x11055a0:
クローンオブジェクトのスロットに変数やメソッドが追加される
クローン(dog)に何か追加するとどうなる? クローンされたオブジェクト dog を調べよう しかし、元オブジェクトにある変数 a は dog slotSummary しても リストされません。Io> dog slotSummary ==> Object_0x111a5c0: 変数を追加してみよう 一方、dog 上で新たに b という変数を作った場合は、 しっかりdog のスロットに bがリストされてます。 これは dogだけが使える変数です。Io> dog b := 7 ==> 7 |
dog のスロットはどうなっているのか調べてみます dog に変数 bを追加後の状態 クローン元から bを呼び出すことはできません。 ということは、dog のスロットは dog 固有の変数やメソッドだけが登録されるようです。Io> dog slotSummary ==> Object_0x111a5c0: b = 7 <-----こいつに注目 // dog の 変数 b にアクセスしてみよう。 Io> dog b ==> 7 // dog 以外から b を呼び出そうとするとエラー Io> b Exception: Object does not respond to 'b' --------- Object b Command Line 1 では、クローン元に何か追加された場合どうなるか? 例えば、この後、クローン元で c という変数が作られた場合 dog から dog c で呼び出することができます。 またクローン元にも同じ名前の変数があった場合、 代入や作成が行なわれた場合、オブジェクト固有のものが優先されるようです。 |
最初に定義しておいて、あとで何度も呼び出せる、 サブルーチン的なものです。 dog にメソッドを追加してみよう この犬はwanwan と吠えることができます。 追加したメソッドを実行してみましょうIo> dog bark := method("wanwan" print) ==> method( "wanwan" print barkは dog だけが使えるメソッド。 Io>dog bark ==>wanwan |
今現在の dog のスロットの状態を調べますbark というメソッドが、dogのスロットに追加されているIo> dog slotSummary ==> Object_0x111a5c0: bark = method(...) <-----こいつに注目 b = 7 メソッドと引数メソッドには、引数が有るものと、無いものを作る事ができます。今回の bark というメソッドは後者です。引数arg は、コンマで区切りられ、一番最後にあるmessage がメッセージ(本体)として機能します。 method_name := method(arg,arg, message ... ) method_name(5,8); メソッドと戻り値Iolanguageのメソッドの構造は次のようになっています。method_name := method(arg,arg, message ... ) この、message の部分には、スペースや改行によって連なるメッセージである aaa bbb ccc とか aaa bbb ccc という書式があてはまります。 Iolangageのメソッドでは、基本的にメソッドの最後にあるメッセージ(ccc)がメソッドの戻り値として認識されるという特徴があります。 return メッセージ ユーザーがメソッドに任意のメッセージを戻り値に指定することもできます message中でreturnメッセージを使います。 return value; hogehoge すると、メソッドのvalueという値が戻り値になります。 このとき 最後にあるメッセージhogehogeは戻り値にはなりません。 複数の複数の戻り値を返すには、今思いつくのは、Listオブジェクトを使って返すくらい? |
メソッドの内容(コード)を出力します。Io> dog getSlot("bark") //結果 method("wanwan" print) Io>
すると、5という値で上書きされて、 以降 dog bark は、5 という値を返すようになります。dog bark = 5
Io>dog bark ==>5
アルファベット大文字小文字昇順
Objectのクローンから カメと魚を作ってみましょう。Io> turtle := Object clone ==> Object_0x5f4e10: Io> fish := Object clone ==> Object_0x5d5120: |
slotSummaryを使って今の状態を調べます
このことから、スロットにはIo> slotSummary ==> Object_0x50c5b0: Lobby = Object_0x50c5b0 Protos = Object_0x50c0c0 a = 5 c = 8 dog = Object_0x111a5c0 exit = method(...) fish = Object_0x5d5120 <------注目 forward = method(...) turtle = Object_0x5f4e10<------注目 英大文字ABC〜XYZ、小文字abc〜xyzの順番で 名前が並ぶことが分かりました。 |
クローンのローカルスコープにある変数はどうなるか
カメのクローンからミュータント・タートルを作ってみましょう。 クローンとして作り出された関係は Object → カメ → ミュータントタートル となっています。 Io> mutantturtle := turtle clone ==> Object_0x595570: Io> slotSummary ==> Object_0x50c5b0: Lobby = Object_0x50c5b0 Protos = Object_0x50c0c0 a = 5 c = 8 dog = Object_0x111a5c0 exit = method(...) fish = Object_0x5d5120 forward = method(...) mutantturtle = Object_0x595570 <----こいつに注目 turtle = Object_0x5f4e10 |
同名の変数があったらどうなるか? 変数 b には root_b という文字列が入っていますが、 dog オブジェクトでは既に変数 b は宣言されています。 このとき、dog にある変数 b, fish にある変数 b , mutantturtleにある変数 b にアクセスすると それぞれどんな結果が返ってくるでしょう? dogの例を見ると、クローン元と同じ名前の変数に代入、作成が行なわれた場合、 オブジェクト固有の変数の作成/読取のほうが、優先されるようです。// 大元のオブジェクトで 変数 b を作る。 Io> b := "root_b" ==> root_b // それそれの結果は? Io> dog b ==> 7 Io> fish b ==> root_b Io> mutantturtle b ==> root_b Io> |
エラー等に反応し、メッセージを返す特殊なメソッド。カスタマイズして使う。
forwardメソッド とは? ここで最初のほうで登場したforward メソッドの謎にせまります。 これはexit メソッドと一緒で少し特殊なメソッドです。 Iolanguageのリファレンスページの例を元に、 Object のクローンである dog オブジェクトの forward メソッドを上書きし、エラーを詳細にフォローするログを書き出させるよう カスタマイズしてみましょう。 dog forward := method( write("sender = ", call sender, "\n") write("message name = ", call message name, "\n") args := call message argsEvaluatedIn(call sender) args foreach(i, v, write("arg", i, " = ", v, "\n") ) ) |
forwardメソッドはどう動くか? ここで、Object のクローンである fish と dog に わざと、存在しないメッセージ bar を送ります。 (fish のfowardメソッドには何も細工していません。) fish は普通のエラーメッセージが返ります。 一方 forward メソッドをカスタマイズした dog はどうでしょう?Io> fish bar Exception: Object does not respond to 'bar' --------- Object bar Command Line 1 Io> dog bar sender = Object_0x50c5b0: Lobby = Object_0x50c5b0 Protos = Object_0x50c0c0 a = 85 cat = Object_0x5b0e60 dog = Object_0x5bbf40 exit = method(...) forward = method(...) mutantdog = Object_0x533d10 message name = bar ==> nil Io> |
Object って何?
さて、dog も turtle も fish も、あらゆるオブジェクトも
のように、Object のクローンとして作られていますが、 Object とは一体なんでしょう?hoge := Object clone |
Ioの対話モードを使って大元のオブジェクトの内容を見ることができます。。。 Objectの内容を見たいなら単純に打つだけです。 予約済みの命令がリストされています。Io>Object ==> Object_0x5003d0: = Object_() != = Object_!=() - = Object_-() .. = method(arg, ...) < = Object_<() <= = Object_<=() == = Object_==() : (中略) : while = Object_while() write = Object_write() writeln = Object_writeln() yield = method(...) if や else のような制御構文や、print 、for 、while とか演算子まであります。 Object には、プログラムに必要な if やfor 、print というメッセージ(命令)があらかじめ用意されいることがわかります。 オブジェクトがどんなメッセージを扱えるかを把握するにはここを見るとよいでしょう。 参考として、オブジェクトにはどんなデータ型があるか調べる方法 >Protos Core |
Object clone も animal food もメッセージを送受信する関係です。animal := Object clone; animal food := 5
■→■→■→■→■→■→■→■→■→■→■→■→■→
animal dog := method(a, a+5); animal kennel := method(food/2); animal cat := method( self *8 ); ← respond できないので使うとエラー( 下のとは異なるオブジェクトになる ) animal Number cat :=method(self*8); ← 正解( ただし、これは animal オブジェクトのスロットには現れません)
arg ↓ dog(...)→
animal dog := method(a, a+5); Io> animal dog(1) dog(1) dog(1) ×エラー Io> animal dog(1) animal dog(1) animal dog(1) //これなら一応動く ==> 6 //この場合、メッセージの連鎖はあっても結果の引継ぎがないので、 最後のメソッドの結果=6 だけが残ります。 Io> animal dog( animal dog(animal dog(0) ) ) ==> 15 //メソッド同士をどうしても 連携させたい場合は、 このように入れ子で書けば、結果が引継がれます。
selfを受け取るメソッドは、型を意識しなければいけません。message→cat(self)→
animal Number cat :=method(self*8); Io> cat cat cat // 最初のオブジェクト(Number型)が存在しないので エラー Io>"Tom" cat // オブジェクトの型が違うのでエラー
animal dog := method(a, a+5); animal Number cat :=method(self*8); Io> 2 cat cat cat // 最初のオブジェクト「2」は Number型 なので連鎖が成立。(2*8*8*8 =1024) ==> 1024 Io> Io> animal dog(1) cat // dog はNunber型を返すから OK( 1+5*8=48 ) ==> 48 Io> result := animal 12 cat println; // 他のメソッドprintln と組み合わせることもできます。 96 ==> 96
Io>result :=animal dog(1); result := result cat; result println; ==> 48
このメソッドadd は、上のようなメッセージング構造を持ちます。arg ↓ message→add(... , self)→
a := 10 b := 20 Number add := method( a , self *2+a ); Io> a add(2) ==> 22 Io> a add(0) ==> 20 Io> b add(2) ==> 42 Io> 10 add(5) ==> 25
a := 10 b := 20 Number add := method( a , self *2+a ); Sequence concat := method(a, self .. a ) Io> "abc" concat("bbb") ==> abcbbb // メッセージをうまく連鎖させるために、間に asStringを挟んで数字を文字列にする。 Io> a asString concat("foobar") ==> 10foobar // ちょっと変えてみる。asStringの前の 括弧は必要です。 Number add := method( a , (self *2+a) asString); // 途中で、オブジェクト型が数値→文字列に変化しています。 Io> 10 add(5) concat("foobar")
A := Object clone // 例によって、オブジェクト名の最初の文字は大文字にします。 B := Object clone Io> A ==> A_0x5ee2f0: // ← Io 側には、正しく オブジェクトA と認識されている type = "A"
(※ 特定のオブジェクトを指定せずに、単独で meth すると大元のobject上にslotが作成されてしまうので注意が必要です。)meth := method( self seq := "aaa"; self num :=5; self lis:=list(); self //次のメッセージに渡すために必要。 )
meth2 := method( // オブジェクトA以外なら、すぐにメソッドを終了。 if(self type != "A" , "オブジェクトの型がちがう〜!" print; return ) self seq := "hoge" self num := num* 10; self lis:=list(1,2,3,4,5); self //次のメッセージに渡すために必要。 )
// 一方こちらはBlock 、 blo call で呼び出せますが、使い道が分からない... blo := block( self seq := "bbb"; self num :=1000; self lis:=list(); self )
Io> B meth2 オブジェクトの型がちがう〜!==> nil // 従って 値は変更されません。
これらメソッドの特徴を把握しておけば、ある程度のiolanguageのコードを読解することができると思います。Io> A meth meth2 ==> A_0x5ee2f0: lis = list(1, 2, 3, 4, 5) num = 50 seq = "hoge" type = "A"
obj := Object clone // 引数型メソッドに渡されるメッセージを調べる obj wtf := method( a , call sender println "L-------------- is sender" println " " println call message println call message name println /* call message previous println call message next println call message next next println call message next next name println */ call message argAt(0) println "L------------- is message, etc" println " " println call activated println "L-------------- is activate" println " " println call slotContext println "L-------------- is contex" println " " println call target println "L-------------- is target" println " " println ) |
// self型メソッドに渡されるメッセージを調べる obj := Object clone obj Number wtn := method( call sender println "L------------- is sender" println " " println call message println call message argAt(0) println "L------------- is message" println " " println call activated println "L------------- is activate" println " " println call slotContext println "L------------- is contex" println " " println call target println "L------------- is target" println " " println self +1 ) |
/ | 引数型メソッド | self型メソッド |
コード | obj wtf(obj b) | 2 wtn println |
call sender | Lobby | Lobby |
call message | wtf(obj b) | wtn println |
call message call message name call message At(0) |
wtf(5) wtf 5 | なし |
call message call message name call message At(0) |
wtf(obj b) wtf obj b | なし |
call message previous call message next |
obj なし |
2 println |
call activated | wtfメソッド の内容 | wtn メソッド の内容 |
call contextSlot |
Objオブジェクト Object_0x5bbe40: b = 1 wtf = method(a, ...) | 0 |
call target |
Objオブジェクト Object_0x5bbe40: b = 1 wtf = method(a, ...) | 2 |
/ | do | method | block |
スタイル | do( ... ) | method( ... ) | block( ... ) |
置かれる場所 | Lobby? | proto | self |
挙動 | すぐやる |
メッセージが 届けばやる |
"block名 call" で、初めて実行。 |
Io> lists := list(1, 2, 3, 4, 5, 6) ==> list(1, 2, 3, 4, 5, 6)
Io> lists at(1) ==>2
Io> lists size ==>6
Io> "aaa bbb ccc dde" split ==> list("aaa", "bbb", "ccc", "dde")
Range//Rangeアドオンを有効にする 1 to(5) asList ==> list(1, 2, 3, 4, 5)
Flux アドオンをロードするこれで、読込まれました。Io> Flux ==> Flux_0x1196810: Views = Object_0x11967d0 fluxPath = "/usr/local/lib/io/addons/Flux" fluxSource = "/usr/local/lib/io/addons/Flux/io/Flux" fluxViews = "/usr/local/lib/io/addons/Flux/io/Flux/Views" loadAll = method(...) type = "Flux" これはプログラムモードでの #!/usr/bin/env io Flux というコードと同じです。 |
このとき、Addons スロットには、Flux に関係するアドオンのオブジェクトが読込まれます。
Io> Addons ==> Object_0x50c820: Box = Object_0x5ff0d0 Cairo = Object_0x5eeb90 EditLine = Object_0x56e9a0 Flux = Object_0x11daea0 Font = Object_0x11999f0 Image = Object_0x5c53a0 OpenGL = Object_0x5f9120 ReadLine = Object_0x111d130 //しかし slotには変化は無い。 Io> slotSummary ==> Object_0x50c5b0: Lobby = Object_0x50c5b0 Protos = Object_0x50c0c0 exit = method(...) forward = method(...) |
オブジェクトを作るとスロットに変化がIo> fooApp := Application clone ==> Application_0x11d1250: mainWindow = OSWindow_0x11b7600 timers = Map_0x11d32b0 windows = list(OSWindow_0x11b7600) 現れます→ 参考:Application オブジェクト fooApp というアプリケーションオブジェクト が 作られました。Io> Application ==> Application_0x2838670: addWindow = method(w, ...) appDidStart = method(...) currentWindow = method(...) display = method(...) firstResponder = nil fonts = Object_0x117f680 init = method(...) keyboard = method(key, x, y, ...) mainWindow = nil motion = method(x, y, ...) mouse = method(b, s, x, y, ...) newWindow = method(...) reshape = method(w, h, ...) run = method(...) screenHeight = method(...) screenWidth = method(...) setFirstResponder = method(...) setMainWindow = method(...) setStarted = method(...) setTimers = method(...) setTitle = method(title, ...) setWindows = method(...) special = method(key, x, y, ...) started = false timer = method(id, ...) timers = Map_0x116a1e0 title = "" type = "Application" windows = list() |
ウインドウ等のオブジェクトが用意されたことを意味します。Io> slotSummary ==> Object_0x50c5b0: Lobby = Object_0x50c5b0 Protos = Object_0x50c0c0 Application = Application_0x117c960 <--------注目 GLObject = GLObject_0x5608b0 <--------注目 OSWindow = OSWindow_0x11c0320 <--------注目 Responder = Responder_0x1165690 <--------注目 View = View_0x11b2890 <--------注目 fooApp = Application_0x11d1250 <------- fooApp exit = method(...) forward = method(...) これで プロパティ(ウインドウ表示位置や、タイトルバーの文字列など)を設定することがきます。 |
Applicationから作ったクローンオブジェクト をrun して 初めてウインドウが表示される。 先ほど、Io> fooApp := Application clone したものを実行してみます これはプログラムモードでのIo>fooApp run #!/usr/bin/env io Flux fooApp := Application clone fooApp run というコードと同じです。 |
すると内容がないウインドウが現れました。![]() Ioのサンプルプログラムを見ると分かりますが、 すべての処理の記述の一番最後に、この run メソッドが呼ばれています。 |
Flux で ウインドウ アプリケーションを作った場合も この方法で、オブジェクトを把握することが出来ます。#!/usr/bin/env io write( getSlot( "Addons" ) , "\n") write( getSlot( "DrawText context" ) , "\n") write( slotNames , "\n") write( slotSummary , "\n")
TextFieldのクローン オブジェクトが生成されると、init メソッドが実行されます。// まず、アプリケーションオブジェクト fooApp を作成しておきます。 fooApp := Application clone // TextFieldオブジェクトを作成する text := TextField clone do (position set(10, 210); size set(190, 32)) // フォントはOpenGL のテクスチャとして描画されます。 //しかしながら日本語の表示はデフォルトでは対応してません。 text font := TextField fonts system mono text textColor set(0.8 , 0.8 , 0.8, 1)// 文字色を指定しないと真っ黒に text setString("Hello World" asString)// 表示する文字列 // addSubviewメソッドでTextField オブジェクトを取込めば画面に表示される // これは他のGUI部品にもいえます。 fooApp mainWindow contentView addSubview(text)
#!/usr/bin/env io Flux // バックと文字色を設定し直した。 Controller := Object clone do( push := method(button, button setTitle("Please don't push this button again.") ) ) app := Application clone app appDidStart := method( app mainWindow setTitle("Test") b := Button clone b setTitle("Foo") b setWidth(300) b setActionTarget(Controller) b setAction("push") b textColor = Color clone set(1, 1, 1, 1) app mainWindow addSubview(b) app mainWindow backgroundColor set(0.5,0.5,0.5, .1) ) app run
ダイアログ//ボタン定義 btn := Button clone do( position set(5, 400) // ウインドウの左下が(0,0) size set(48, 32) font := TextField fonts system mono roundingSize := 40 selectedColor := Color clone set(.3,.3,.3, 1)//選択された時の色 setAction("pushButton") textColor set(1,1,1,1) //必ず文字色を指定する。 setTitle("btn") // ボタンの文字 ) fooApp mainWindow contentView addSubview(btn) //ウインドウに追加
alert := AlertPanel clone alert position set(40,51) alert text = "Warning Texts" alert okButton setTitle("OK") alert cancelButton setTitle("Cancel") //okAction //cancelAction fooApp mainWindow contentView addSubview(alert) gui_obj := Label clone gui_obj resizeHeight := 031 gui_obj resizeWidth := 031 gui_obj size set(80, 80) gui_obj position set(40,51) gui_obj title = "hogehoge" fooApp mainWindow contentView addSubview(gui_obj)
メソッドが用意されています。placeAbove( objname ) placeBelow( objname ) placeRightOf( objname ) placeLeftOf( objname ) placeLeftOf( objname )
つまりIoにおいても同じような作法に従えばよいことになります。1. サーフェス (Cairo::Surface) を作成する。 2. 作成したサーフェス用のコンテキスト (Cairo::Context) を作成する。 3. コンテキストに対して描画処理を行う。 4. サーフェスに終了メッセージを送る。 -- 引用終わり--
オブジェクト: = Object clone do(
<<Cairoのprotoを追加>>
サーフェス surface := Image/PDFSurface create( サーフェスのサイズ )
コンテキスト Context create(surface) do(
<<Cairoのprotoを追加>>
<<描画コマンド>>
showPage
)
surface finish --- PDFの場合 サーフェスに終了メッセージを送る。
)
#!/usr/bin/env io Cairo_draw := Object clone Cairo_draw context := do( appendProto(Cairo) //Cairoの機能を用意する surface := ImageSurface create(FORMAT_ARGB32, 256, 256) // サーフェスを作成することができる(格納形式、縦、横) Context create(surface) do( //サーフェス用のコンテキストを作成 appendProto(Cairo) //このコンテキストでもCairoの機能を使えるようにする //以下、サーフェスのコンテキスト上で描画指定する。 scale(256, 256) setLineWidth(0.04) // システムにあるフォントをロード selectFontFace("Apple_osaka_unicode", FONT_SLANT_NORMAL, FONT_WEIGHT_BOLD) setFontSize(0.25) moveTo(0.04, 0.53) showText("あぅ〜") getTarget writeToPNG("aaa.png") //IoCairo_makePng.ioと同じディレクトリに PNG画像で出力 ) )
#!/usr/bin/env io Cairo_draw := Object clone Cairo_draw context := do( appendProto(Cairo) //Cairoの機能を用意する、これで↓ // PDF用のサーフェスを作成 (大きさは W400xH200ピクセル) 出力ファイル名もここで設定する surface := PDFSurface create("output.pdf" , 400,200) Context create(surface) do( //サーフェス用のコンテキストを作成 appendProto(Cairo) //このコンテキストでもCairoの機能を使えるようにする //以下、サーフェスのコンテキスト上で描画指定する。 scale(256, 256) //倍率 setLineWidth(0.04) // システムにあるフォントをロード selectFontFace("Apple_osaka_unicode", FONT_SLANT_NORMAL, FONT_WEIGHT_BOLD) setFontSize(0.12) moveTo(0.04, 0.13) showText("Hello World こんにちわ。") moveTo(0.04, 0.23) setFontSize(0.08) showText("日本語の文章をPDF形式で、書き出し。") showPage // これもやっておきます。 ) surface finish // これが無いとPDFがうまく出力されません。 )
#!/usr/bin/env io Flux ResourceManager ImageManager addPath(Path with(".","resources/themes/Neos")) fooApp := Application clone Cairo_draw := Object clone Cairo_draw context := do( appendProto(Cairo) //Cairoの機能を用意する、これで↓ // surface:= ImageSurface createFromPNG(Path with("data", "romedalen.png")) //試験用 surface := ImageSurface create(FORMAT_ARGB32, 256, 127) // サーフェスを作成することができる(格納形式、縦、横) Context create(surface) do( //サーフェス用のコンテキストを作成 //このコンテキストでもCairoの機能を使えるようにする appendProto(Cairo) //以下、サーフェスのコンテキスト上で描画指定する。 // Cairo Surfaceの前処理(これが無いとダメ) scale(256,256) // 表示比率は 1:1 にする。 これが無いと、アルファチャンネルが反転して真っ赤になる(原因不明)。 // setSourceRGB(0.5, 0.5, 1) // サーフェス背景塗りつぶし用の色 // rectangle( 0,0,256,100 ) // 塗りつぶしが無ければ、背景は透明になる // paint // 背景塗りつぶし用 //以下、文字を描画 moveTo(x,y) setSourceRGB(1, 1 ,1) //文字色 setLineWidth(0.04) selectFontFace("Apple_osaka_unicode", FONT_SLANT_NORMAL, FONT_WEIGHT_BOLD)//フォント指定 setFontSize(0.12) moveTo(0.08,0.14) showText("CairoSurface上の") moveTo(0.04,0.23) setFontSize(0.08) showText("文字をFluxのGUIへ描画。") setSourceSurface(surface ,0,0) // これがないと表示されません ) // Flux の ImageViewオブジェクトを作成 // これはGUI上でイメージを表示するためのオブジェクト img := ImageView clone do( position set(50, 15); // 実際のウインドウ上に表示される位置(左下隅がX:0,Y:0 ) size set(256, 127) ) // イメージオブジェクトを作成(作業用) //setData〜Count メソッドを使い Cairo Surface データを、Image オブジェクトへ渡す。 outd := Image clone outd setDataWidthHeightComponentCount( surface getData,surface getWidth, surface getHeight,4) // Imageオブジェクトをさらに ImageViewオブジェクトへ渡す。 img image = outd // img setImage(Image clone open(Path with(".", "hogehoge.png"))) //←普通に画像を表示させる場合 fooApp mainWindow contentView addSubview(img )// ウインドウ上に表示させる。 ) fooApp mainWindow size set(350, 200) fooApp mainWindow backgroundColor set(0.5 , 0.5 , 0.5 , 0.1) fooApp run
FluxアドオンのApplicationオブジェクト | OpenGLアドオンのGLAppオブジェクト | |
---|---|---|
どちらのタイプも、GLUTウインドウアプリケーション立ち上げまでは自動でしてくれます。 | ||
Flux アドオンで定義されている (Iolanguage のFlux GUITool Kit、GUIを含め、高度なことができる) |
OpenGLアドオンで定義されている (シンプルなGLUTウインドウアプリケーション) | |
timerスロットあり mouseスロットあり keyboadスロットあり |
timerスロット:=nil mouseスロット:=nil keyboadスロットあり | |
オブジェクトごとに機能が分担されている (OSwindows.io,Screen.io, Views.io) 便利なメソッドも用意されている (Screen.io) set3dPerspective set2dPerspective Screen.io のほうで初期化 glutKeyboardFunc glutSpecialFunc glutMotionFunc glutMouseFunc |
GLApp.ioで、すべて定義 GLUTの初期化に必要な手続きは自動で行なわれます。 glutKeyboardFunc glutSpecialFunc glutMotionFunc glutMouseFunc 必要な処理は自分で追加しなければいけません。 |
ResourceManager
ResourceManagerからは、2つのマネージャがクローンとして派生しています。 ImageManager 認識する拡張子(png,jpg,tiff)が、addSuffixで登録されています。 addPath メソッドでは、OSX, Milk , Neosの三種類のテーマから設定されます。 Imageアドオンの機能も利用されます。 なお、Flux アドオンのインターフェース要素であるチェックボックスは、イメージ画像の取得にこれを使っています。 FontManager 認識する拡張子(ttf)が、addSuffixで登録されています。 Fontアドオンの機能も利用されます。 これは、Ioアドオンのソースファイルを見るとわかります。 /stevedekorte/addons/OpenGL/io/ResourceManager.io
Context create(outputSurface) scale(w / width, h / height) setSourceSurface(inputSurface, 0, 0) paintいきなり登場した Context が何なのか、まずはその出所から調べてみましょう。Io の対話モードの出番です。 Io> Cairo するか、Io> Cairo Context して、slot の内容が調べると、Context は、Cairo アドオンを有効にすると登場するオブジェクトだと判明します。 さらに、Io> Cairo Context すると、scaleも、setSourceSurface も pain も Context に係るメソッドだと分かります。 よって、この文章は、 Context に対して、 outputSurface を create してから、 高さと幅をそれぞれw,hで割った縮尺に scale してから 、 iputSurface の0,0 へ画像データを setSourceSurface してから、 paint する。と読み解けます。 (※チェインの矢印はオブジェクトとメソッド関係を表すものです、実際の処理は左から右へと順番に行なわれます)
![]()
Directory with(Flux fluxSource) files select(name endsWithSeq(".io")) foreach(f, self doFile(f path) )このコード断片は一体どんな処理を意味しているのでしょうか?
Io> Flux Io> Importer addSearchPath(Flux fluxSource) ==> list("", "/Users/usr", "/usr/local/lib/io/addons/Flux/io/Flux", "/usr/local/lib/io/addons/Flux/io/Flux/Views") Io> Directory with(Flux fluxSource) files ==> list(File_0x11bc100, File_0x11bb0e0, ...略... , File_0x11d6b40 ) Io> Directory with(Flux fluxSource) fileNames ==> list(".DS_Store", "Action.io", "Application.io", "Keyboard.io", ...略... , "TextureSet.io", "View.io") Io> Directory with(Flux fluxSource) files select(name endsWithSeq(".io")) foreach(f, self doFile(f path) )時間があれば、対話モードを使って、コードがどのように動作するのかを、感覚的につかむことができます。
(※チェインの矢印はオブジェクトとメソッド関係を表すものです、実際の処理は左から右へと順番に行なわれます) (※ select() や foreach()メソッドは様々なオブジェクトからも利用することができますが、 この図では、連鎖後の結果から select()とforeachをListオブジェクトのメソッドとして分類しています。)
●name はメソッド//今回のDirectory with〜 files メソッドは、リストオブジェクトを返しますがリストの中に入っているのは、実はFileオブジェクトです 。 // 試しに、リストから1要素を取り出してみましょう。 Io> Directory with(Flux fluxSource) files at(1) ==> File_0x11dbc20:
●path も FileオブジェクトのメソッドIo>Directory with(Flux fluxSource) files at(1) name ==>Action.io
File pathメソッドはFileオブジェクトを、ファイルパス文字列(Sequenceオブジェクト)に変換する機能を持つことがわかりました。Io> Directory with(Flux fluxSource) files at(1) path ==> /usr/local/lib/io/addons/Flux/io/Flux/Action.io
●Fileオブジェクトのメソッドは一般的なファイルの出入力担当。//指定したファイルパスを、 ファイルオブジェクトにするFile with(...)メソッド a := File with("File/path/String.ext") ==> File_0x5a51a0: //逆に元の文字列に戻すFile pathメソッド(メッセージ) a path ==> "File/path/String.ext"
アクタ(Actor)の持つ機能(Wikipediaより引用)
- (他の)アクタに有限個のメッセージを送信する。
- 有限個の新たなアクタを生成する。
- 次に受信するメッセージに対する動作を指定する。
スケジューラの管理下で、非同期メッセージによって、メソッドAとBが交互に行なわれ、最終的にFutureの内容が確定した段階で結果が表示されるようです。// メソッドの所属するオブジェクトに注意する。 obj1 := Object clone do( # Future Coroutine # ↓ ↓ a := method( list("o","a","o","u","o","a","i","a","u") foreach(a,a print;yield) ) ) obj2 := Object clone do( # Future Coroutine # ↓ ↓ b := method( list("","h","y","","g","z","","m","s") foreach(a,a print;yield) ) ) obj1 @@a; obj2 @@b; /* @a;@b の結果も Future。アクタをセットした段階では実行が保留されています = nil */ #↑ # Actor while(Scheduler yieldingCoros size > 0, yield); // スケジューラの起動により並列処理が開始。訂正 #↑ # Scheduler # ↓ whileを使わなくても Scheduler yield を使えばコルーチンを任意に進行させることができます。 Scheduler yield
※コルーチンが終了しても、coroDoLater() や @ を再度やり直せば、コルーチンはもう一度有効になります。//普通のメッセージの結果 a := method( list("o","a","o","u","o","a","i","a","u") foreach(a,a print) ) b := method( list("","h","y","","g","z","","m","s") foreach(a,a print) ) Io> a oaouoaiau==> u Io> b hygzms==> s Io> a;b oaouoaiauhygzms==> s Io> @a;@b oaouoaiauhygzms==> s
//実験1 //メソッドにyeild を入れてみた。 a := method( list("o","a","o","u","o","a","i","a","u") foreach(a,a print;yield) ) b := method( list("","h","y","","g","z","","m","s") foreach(a,a print;yield) ) Io> a; oaouoaiau==> nil Io> b; hygzms==> nil Io> a;b oaouoaiauhygzms==> nil Io> Io> @a;@b oaouoaiauhygzms oaouoaiauhygzms==> nil // a→b , b→a コルーチン同士を二回渡っている?
//並列処理を行なうにはスケジューラを使う必要がある。 // 失敗例 // Object直下では、スケジューラはうまく動作しないようです。 a := method( list("o","a","o","u","o","a","i","a","u") foreach(a,a print;yield) ) b := method( list("","h","y","","g","z","","m","s") foreach(a,a print;yield) ) @a;@b; ooaouoaiauaouoaiauhygzms==> nil while(Scheduler yieldingCoros size > 0, yield) ==> nil
// それなら、Objectのクローンオブジェクト上に、コルーチンを作ってみたらどうか? // 失敗例 // スケジューラは起動、しかし意図したようには動作しません…。 obj1 := Object clone do( la := list("o","a","o","u","o","a","i","a","u"); lb := list("","h","y","","g","z","","m","s"); a := method( for(a, 0, 8 , la at(a) print;yield) ); b := method( for(b, 0, 8 , lb at(b) print;yield) ); ) obj1 @@a; obj1 @@b;nil; while(Scheduler yieldingCoros size > 0, yield); ooaaoouuooaaiiaauuhhyyggzzmmss==> Coroutine_0x5755e0: parentCoroutine = Coroutine_0x118b120 result = false runLocals = Object_0x1149ed0 runMessage = future setResult(self doMessage(futur... runTarget = Object_0x1149ed0 Io>
//今度は異なるオブジェクトObj1、Obj2 にあるメソッドを、コルーチンとして並列処理してみた。 // 成功例 // やっと意図したように動作しました。 obj1 := Object clone do( la := list("o","a","o","u","o","a","i","a","u"); a := method( for(a, 0, 8 , la at(a) print;yield) ); ) obj2 := Object clone do( lb := list("","h","y","","g","z","","m","s"); b := method( for(b, 0, 8 , lb at(b) print;yield) ); ) obj1 @@a; obj2 @@b;nil; while(Scheduler yieldingCoros size > 0, yield); ohayougozaimasu==> Coroutine_0x5fb2d0: parentCoroutine = Coroutine_0x5e6850 result = false runLocals = Object_0x1112b40 runMessage = future setResult(self doMessage(futur... runTarget = Object_0x1112b40
obj1 := Object clone do( la := list("o","a","o","u","o","a","i","a","u"); a := method( for(a, 0, 8 , la at(a) print;yield) ); ) obj2 := Object clone do( lb := list("","h","y","","g","z","","m","s"); b := method( for(b, 0, 8 , lb at(b) print; yield) ); ) obj1 @@a; obj2 @@b;nil; while(Scheduler yieldingCoros size > 0, writeln("---------- Yielding Output ---------- "); yield writeln("--> ", Coroutine yieldingCoros size, " \n", Coroutine yieldingCoros map(backTraceString) ); );
---------- Yielding Output ---------- o--> 2 list(" --------- Coroutine yield Actor.io 89 Object yield Command Line 3 Object b Command Line 1 Future setResult Actor.io 121 ", " --------- Coroutine yield Actor.io 89 Object yield Command Line 3 Object a Command Line 1 Future setResult Actor.io 121 ") ---------- Yielding Output ---------- ha--> 2 list(" --------- Coroutine yield Actor.io 89 Object yield Command Line 3 Object b Command Line 1 Future setResult Actor.io 121 ", " --------- Coroutine yield Actor.io 89 Object yield Command Line 3 Object a Command Line 1 Future setResult Actor.io 121 ") : (略) : ---------- Yielding Output ---------- --> 0 list() ==> nil
後は、Scheduler yield する度にコルーチンが交互に、1回づつ呼び出されています。obj1 := Object clone do( la := list("o","a","o","u","o","a","i","a","u"); a := method( for(a, 0, 8 , la at(a) print;yield) ); ) obj2 := Object clone do( lb := list("","h","y","","g","z","","m","s"); b := method( for(b, 0, 8 , lb at(b) print; yield) ); ) coro1 := coroDoLater(obj1 a )//コルーチン化 coro2 := coroDoLater(obj2 b ) Scheduler setYieldingCoros( list( coro1,coro2 ) );//スケジューラにコルーチンを登録 Scheduler yield //スケジューラを起動
《参考》《実行結果》 Io> Scheduler yield o ==> Coroutine_0x559f80: runLocals = Object_0x50c5b0 runMessage = obj2 b runTarget = Object_0x50c5b0 Io> Scheduler yield ha ==> Coroutine_0x559f80: runLocals = Object_0x50c5b0 runMessage = obj2 b runTarget = Object_0x50c5b0 Io> Scheduler yield yo ==> Coroutine_0x559f80: runLocals = Object_0x50c5b0 runMessage = obj2 b runTarget = Object_0x50c5b0 Io> Scheduler yield u ==> Coroutine_0x559f80: runLocals = Object_0x50c5b0 runMessage = obj2 b runTarget = Object_0x50c5b0
// アクタを使わないで、コルーチンを制御。 obj1 := Object clone do( la := list("o","a","o","u","o","a","i","a","u"); a := method( for(a, 0, 18 , "a" print;yield) ); // このコルーチンに来たら "a" と言う文字を表示する ) obj2 := Object clone do( lb := list("","h","y","","g","z","","m","s"); b := method( for(b, 0, 18 , "b" print; yield) ); // このコルーチンに来たら "b" と言う文字を表示する ) coro1 := coroDoLater(obj1 a )//コルーチン1を生成 coro2 := coroDoLater(obj2 b )//コルーチン1を生成 Scheduler setYieldingCoros( list( coro1,coro2 ) );//スケジューラにコルーチンを登録 //Scheduler yield スケジューラを進める。 //coro1 pause コルーチン1を停止 //coro1 resumeLater コルーチン1を再開(スタックに再登録される) //余計な表示を出さないように、一括メッセージにしています。 "Coros ----Start " println Scheduler yield Scheduler yield Scheduler yield coro1 pause "\n coro1 pause----" println Scheduler yield Scheduler yield Scheduler yield Scheduler yield Scheduler yield Scheduler yield "\n coro1 resumeLater----" println coro1 resumeLater Scheduler yield Scheduler yield Scheduler yield Scheduler yield Scheduler yield 《実行結果》 Coros ----Start //並列動作 交互に呼び出されている。 bababa coro1 pause (a) //ここで、コルーチン1(a)を停止すると b だけが呼び出される。 bbbbbb coro1 resumeLater (a)// コルーチン1(a)を復活させると、再び交互に呼び出されている。 ababababab==> Coroutine_0x1167750: runLocals = Object_0x50c5b0 runMessage = obj1 a runTarget = Object_0x50c5b0 Io>
@(アクタ) を使用したコルーチン | coroDoLater()を使用したコルーチン |
アクタの最終結果は、 Futureオブジェクトが受け取る。writeln("--> ", Coroutine yieldingCoros size, " \n", Coroutine yieldingCoros map(backTraceString) ); ha--> 2 list(" --------- Coroutine yield Actor.io 89 Object yield Command Line 3 Object b Command Line 1 Future setResult Actor.io 121 ", " --------- Coroutine yield Actor.io 89 Object yield Command Line 3 Object a Command Line 1 Future setResult Actor.io 121 ") |
Io> Coroutine yieldingCoros map(backTraceString) ==> list(" --------- Coroutine yield Actor.io 89 Object yield Command Line 3 Object b Command Line 1 ", " --------- Coroutine yield Actor.io 89 Object yield Command Line 3 Object a Command Line 1 ") |
Actor.io 63〜65行目 waitingCoros append(Scheduler currentCoroutine) Scheduler currentCoroutine pause Actor.io 89行目 Object do( yield := method(Coroutine currentCoroutine yield)
Actor.io 121行目付近 loop( while(future := actorQueue first, e := try( future setResult(self doMessage(future runMessage)) ←121行目
>Io の Future は透過的だ。すなわち、その結果が使えるようになると、Future は結果自身になる。
> 透過的な FutureTransparent Futures
>自動デッドロック検知Auto deadlock detection --引用終わり--
//コルーチンとなるメソッドabcdは それぞれ 数を並行してカウントする。 yield位置は forループの最初。 A := Object clone do( a := method( m1 , for(i, 1,m1, yield; " a" print; i print); "--(CoroA Fin)--" print ); ); B := Object clone do( b := method( m2 , for(i, 1, m2,yield; " b" print; i print); "--(CoroB Fin)--" print); ); C := Object clone do( c := method( m3 , for(i, 1, m3,yield; " c" print; i print); "--(CoroC Fin)--" print); ); D := Object clone do( d := method( m4 , for(i, 1, m4 ,yield; " d" print; i print); "--(CoroD Fin)--" print); ); //「Scheduler yieldingCoros size % 1」 これはキューの残り1毎に 改行することを意味します。 //D→C→B→Aの順番で残る A @@a(4);B @@b(3);C @@c(2);D @@d(1);while(Scheduler yieldingCoros size >0, yield; if( Scheduler yieldingCoros size % 1 , "" println) );Scheduler yield d1--(CoroD Fin)-- c1 b1 a1 c2--(CoroC Fin)-- b2 a2 b3--(CoroB Fin)-- a3 a4--(CoroA Fin)-- //A→B→C→Dの順番で残る A @@a(1);B @@b(2);C @@c(3);D @@d(4);while(Scheduler yieldingCoros size > 0, yield; if( Scheduler yieldingCoros size % 1 , "" println) );Scheduler yield d1 c1 b1 a1--(CoroA Fin)-- d2 c2 b2--(CoroB Fin)-- d3 c3--(CoroC Fin)-- d4--(CoroD Fin)-- //AとDが1回目で停止 、CとBが3回目で停止 A @@a(1);B @@b(3);C @@c(3);D @@d(1);while(Scheduler yieldingCoros size > 0, yield; if( Scheduler yieldingCoros size % 1 , "" println) );Scheduler yield d1--(CoroD Fin)-- c1 b1 a1--(CoroA Fin)-- c2 b2 c3--(CoroC Fin)-- b3--(CoroB Fin)-- //bだけ最後まで残る A @@a(3);B @@b(5);C @@c(2);D @@d(1);while(Scheduler yieldingCoros size > 0, yield; if( Scheduler yieldingCoros size % 1 , "" println) );Scheduler yield d1--(CoroD Fin)-- c1 b1 a1 c2--(CoroC Fin)-- b2 a2 b3 a3--(CoroA Fin)-- b4 b5--(CoroB Fin)-- // これはどうかな? A @@a( B @@b( C @@c( D @@d(4) )));while(Scheduler yieldingCoros size > 0, yield; if( Scheduler yieldingCoros size % 1 , "" println) );Scheduler yield エラーでした。