From: matz@... (Yukihiro Matsumoto) Date: 2003-03-12T02:08:36+09:00 Subject: [ruby-dev:19799] Re: (1.8.0-preview2) Proc#call In message "[ruby-dev:19798] Re: (1.8.0-preview2) Proc#call" on 03/03/12, Masatoshi SEKI writes: | | |咳といいます。 | |> そのようですね。breakで終了したのか正常終了したのか知る方法 |> が欲しいというニーズに答えるためのようですね。うーむ、難しい。 |> かなりややこしいので咳さんと直接話さないといけないかなあ。 |> どうやって話すかが問題だけど。 | |むむむ。まつもとさんが関東へ来るようなイベントないですかねえ。 |合わせて咳も関東へ行きますよ。 5月(17日?)にアスキーがイベントを行うって行ってました。16日 には情報処理学会のHI研究会ってのがあるんで東京に居ます。 でもちょっと先ですね。 もっと先だと7月にオープンソースカンファレンス(7日から11日、 オレゴン州ポートランド) に出席するんで、東京を経由するんじゃ ないかと。 |ruby-bugs-ja PR#98というのはどこで見られるのでしたっけ。 http://www.ruby-lang.org/cgi-bin/ruby-bugs-ja/ から1.7グループに入ってください。 一応、現状を簡単にまとめると * local jumpにはreturn, next, break, redo, retryがある。 * orphan(孤児)な手続きオブジェクトからのlocal jumpは例外を 発生させることがある。 * orphanとは手続きオブジェクトを作るモトになったブロックを 囲むメソッドが終了してしまっている手続きオブジェクトであ る。 def foo f = lambda{|x| p x} p f # fはまだorphanじゃない return f end f2 = foo() # f2はfooが終了しているのでorphan * returnはブロックを囲むメソッドの末尾にジャンプするため、 orphanな手続きオブジェクトから呼び出されると飛び先が分か らずlocal jump errorになる。 def foo lambda{|x| return x} end foo().call(42) * nextはブロックの実行を中断すし、yield(またはProc#call)が 終了する。1.7ではnextは値を取ることができ、その値はyield の戻り値となる。nextはlocal jump errorにならない。 * breakはブロックが与えられているメソッドの実行を中断する。 1.7ではbreakは値を取ることができ、その値はメソッドの戻り 値となる。ブロックが手続きオブジェクトとなった場合、その 内部でのbreakの挙動には検討の余地がある。※ * redoはブロックの実行の先頭に戻る。redoはlocal jump error にならない。 * retryはブロックが与えられているメソッドの実行をその引数 の評価からやり直す。orphanな手続きオブジェクトから呼び出 されると飛び先が分からずlocal jump errorになる。 f = lambda{retry} f.call さて、ここにorphanな手続きオブジェクトpがあるとします。 このpの実行の仕方は3種類あります。 (1) ブロック引数(&p)を使う (2) callメソッドを使う (3) yieldメソッドを使う これらそれぞれの場合、あるべきlocal jumpの挙動はどうあるべき かを考察します(ただし、nextとredoについては考察の必要はあり ません。不確定な要素がないからです)。 1のブロック引数を使う場合、コードは次のようになります。 5.each(&p) これは本来pが持つブロックをeachメソッドに渡したのと同じ動作 をするべきだと考えます。よって、pの中のbreakはeachの実行を中 断し、retryはeachの実行を最初からやり直しするべきだと考えま す。では、returnはどうでしょう。選択肢は二つあって、ひとつは 「pが持つブロックをeachメソッドに渡したのと同じ動作」という 部分を厳密に考えてeachメソッドがreturnするという挙動、もうひ とつは、return文と返るべきメソッドが遠く離れているのは変だと いうことで、エラーにする挙動。現在の1.8は後者を採用していま す。 2のcallメソッドを使う場合、コードは次のようになります。 p.call この場合、ブロックを実行しているメソッドはcallメソッドになる と解釈するのが自然のような気がします。そうすると可能な選択肢 はそれぞれ A B break callを中断 例外 return 例外 例外 retry callを再実行 例外 です。1.6はBBB、現状の1.8はABBです。使い勝手から考えると returnの例外は決まりのような気がしますが、retryの例外は考慮 の余地があるかもしれません。ABAとかも面白そう。 3のyieldメソッドですが、これは1.7から導入されたものです。使 い方はcallと同じです。 p.yield もともとyieldはcallで行われているパラメータの数の厳密なチェッ クを回避することが目的で、挙動の違いもそれだけでした。しかし、 ruby-bugs-ja PR#98の過程でbreakを例外にするかどうかという違 いも付与されるようになりました。でも、今改めて考えると一つの メソッドに複数の目的を付与するのはやっぱり良くないようにも思 います。もし、可能であればlocal jumpについては上記のABBまた はABAでcallと揃えた方が良いと思います。 さて、となると最終的に考慮しなければならない問題は、dRubyが ネットワークを介してブロックを実行するときbreakやretryを検出 しなければならない時、最低限なにが必要か、という点です。 田中哲さんが以前に例外に依存しない方法を提案していらっしゃっ たと思うのですが、もう忘れちゃったなあ。 まつもと ゆきひろ /:|)