トップ «前の日記(2008-02-07) 最新 次の日記(2008-02-10)» 編集

Route 477



2008-02-08

[ruby] irbコマンドを経由せずにIRBを起動する方法

ruby -rirb -e 'IRB.start'

これでいけるらしい。

[ruby] Fiber#transferについて調べてみた

- Fiber::Core は callcc 並の黒魔術である、とレッテルを貼って使わせない

[[ruby-dev:31596] Re: Fiber reviesedより引用]

黒魔術と聞いてやってきました。

rubyのソースコードのtest/ruby/test_fiber.rbに例があるんですが、これが難しい…。

  def test_transfer
    ary = []
    f2 = nil
    f1 = Fiber.new{
      ary << f2.transfer(:foo)
      :ok
    }
    f2 = Fiber.new{
      ary << f1.transfer(:baz)
      :ng
    }
    assert_equal(:ok, f1.transfer)
    assert_equal([:baz], ary)
  end

とりあえず、Fiberについてのポイントを3つ。

  • Fiber.newしただけではまだ実行されない。
  • Fiber#resumeで実行。実行が終わるか例外が発生すると実行元に戻る。
  • Fiber#transferというのもあって、こっちは実行が終わるか例外が発生するとroot fiber(メインスレッドみたいなもの?)に戻る。

んで、resumeは普通だがtransferは黒魔術らしいw

では、上のソースを読んでみるよ。test_transferを実行すると、

  1. ary = [], f1 = Fiber, f2 = Fiber のように代入される
  2. f1.transfer()が呼ばれ、f1に制御が移る
  3. f2.transfer(:foo)が呼ばれ、f2に制御が移る (このとき、f1の表す仕事は「値をaryに突っ込み、:okを返す」)
  4. f1.transfer(:baz)が呼ばれ、f1に制御が移る (このとき、f2の表す仕事は「値をaryに突っ込み、:ngを返す」)
  5. f1が再開される。渡された値 :baz がaryに突っ込まれ、:ok が返り値になる
  6. f1の実行が終わる。resumeならここでf2に戻るはずだが、transferを使ってるので、root fiberに戻る
  7. assert_equal(:ok, :ok) => テスト成功。やったね

ふむふむ。なんつーか、この実行順序、無茶だよね(笑)。強制的に親元に連れ戻される家出少女のような(意味不明)。

しかし、まだtransferが黒魔術な理由はよくわかってない。 なんとなく、ヤバそうな雰囲気は感じるんだけど。 処理系のスタックの知識があればきっと瞬時に「これがこうなって、こうなったときに危ない」とかイメージできるんだろうなー。

本日のツッコミ(全3件) [ツッコミを入れる]
ku-ma-me (2008-02-09 12:10)

resume でも transfer でも片方だけ使うのはそれほど問題ないんですが、両方同時に使うとカオスになるんです。<br>で、どちらか選ぶなら resume の方がきっといいので、transfer にネガティブなレッテルを貼ってしまえと。<br>ただ callcc の黒魔術と違って、transfer を便利だと思えるような例は思いつかないんですよねえ。

ささだ (2008-02-09 18:26)

状態遷移とかになんか使えないのかなあとかは考えた。<br><br>あと、transfer の状態で例外あがったらどうするのん、とか、そういうのが黒い。

yhara (2008-02-11 12:14)

> 両方同時に使うとカオスになるんです。<br>なるほど、了解です。<br><br>僕もまだtransferの使い方は思いつけてないです。難しい。