From: SASADA Koichi Date: 2007-06-18T10:07:17+09:00 Subject: [ruby-dev:31016] Re: ("a".."f").step(2) {|x| p x}  ささだです。 Yukihiro Matsumoto wrote: > ごめんなさい。「ひとつのスタックフレームには 1 つのブロック渡 > ししか対応していません」というのがなにを意味するのかよくわか > りません。ので、変な制限でないのかどうかの判断もできません。 > rb_iterate()全般が動かないというわけではないようですが、たと > えばeach_with_indexが動いてstepが動かない理由ってのはすぐに > ピンとは来ませんね。  成瀬さん、ソースを読んでくれてありがとうございました。ここで 大事なのは rb_iterate に渡す関数から rb_call0 が呼ばれていない ということです。  rb_iterate が何をするのか、その定義はよくわからなかったので すが、リファレンスマニュアルをみると次のようになっています。 > まず call_proc(data1) を実行します。そしてその関数かその直下のメソッドで yield が発生すると以下が実行されます。  (1)「その関数か」(2)「その直下のメソッド」という定義を、私は (2) だけ、というように実装したということになります。これは、 NODE_ITER の使い方、および enum.c での利用法を見てそのように判 断しました(てっきり、(2) の使い方だけかと思っていた)。(1) に 依存したプログラムってどれくらいあるでしょうか。直すのは結構大 変そうです。  なので、現在の rb_iterate() の仕様による解決方法は str_step() で rb_funcall() で何らかのメソッドを呼べばよいとい うことになります。 ----  「ひとつのスタックフレームには 1 つのブロック渡ししか対応し ていません」の意味ですが、まず ('a' .. 'b').step(2){ (A) } で は、Range#step に、1つのブロック渡しをされています。その時点 で、このスタックフレームには1つのブロックが登録されたことにな ります。  rb_iterate() を実行すると、「次のメソッド呼び出し時に C で記 述したブロックを渡す」という意味となります(同じスタックフレー ムに複数のブロックは積めない)。なので、Range#step 処理中(同 じスタックフレーム)で yield したときの挙動は (A) を呼び出す、 ということになります。たとえば、Range#step が String#step を呼 び出せば、正しく動きます(exclを渡す方法がないんだけど)。 -- // SASADA Koichi at atdot dot net