From: shugo@... (MAEDA Shugo) Date: 1998-11-30T18:11:57+09:00 Subject: [ruby-dev:3704] Re: Multiple assignment at yield() 前田です。 >>>>> In [ruby-dev:3668] >>>>> "松本" == Yukihiro Matsumoto san wrote: 松本> それと,[ruby-list:3625]の問題は本質的にはcallやyieldの引数 松本> が複数与えられた時には(強制的な)配列化を行う定義になっており, 松本> yield a, b 松本> と 松本> yield [a, b] 松本> の区別が付かないことにあります.というか前者は後者の略記法の 松本> つもりだった.これはProc#callにも適用されますから,(少なくと 松本> も現状では)callでも両者の区別はつきません.[ruby-list:3625] 松本> はその区別を求めているわけですから,多重代入をどうこうするだ 松本> けでは不十分で,yieldの実行モデルを再検討しないと解決できな 松本> いのです. Lispで言えば、apply的であり、かつfuncall的でもあるわけですよね。 やはりどちらかに統一した方がよいのではないでしょうか。 apply的なyieldをyield_a、funcall的なyieldをyield_fとすると、 yield_a(list) は、 yield_f(*list) と書けるので、funcall的な動作にするべきではないかと思います。 # 現在のyieldがfuncall的な動作だと思っている人も多いのではない # かという気がしますし。 つまり、 yield(1) #=> args == [1] yield(1, 2) #=> args == [1, 2] yield([1, 2]) #=> args == [[1, 2]] 問題は、現在の仕様ではブロックへの引数の受け渡しに多重代入を 使っているため、このままでは、 [1, 2, 3].each do |i| p i end が、 [1] [2] [3] になってしまうことです。 これを多重継承のロジックを変更することで解決するのは無理が あると思います。 そこで思い切って、ブロックへの引数の受け渡しに多重継承を用いず、 別のロジックを用いることにしてはどうでしょう。 具体的には、 yield(1) (args == [1]): |x| => x = 1 |x,| => x = 1 |*x| => x = [1] yield(1, 2) (args == [1, 2]): |x| => x = 1 |x,| => x = 1 |x,y| => x = 1; y = 2 |*x| => x = [1, 2] yield([1, 2]) (args == [[1, 2]]): |x| => x = [1, 2] |x,| => x = [1, 2] |x,y| => x = [1, 2]; y = nil |*x| => x = [[1, 2]] つまり|x|を|x,|と同じ意味に、|*x|をこれまでの|x|の意味にするわけです。 これなら[ruby-dev:3625]は解決されますし、メソッドの引数の渡し方に 挙動を合わせただけなので、モデルも理解しやすいというか、直感に合って いるような気がします。 # でも、やはり大袈裟すぎるかなあ。 # rb_yield()をどうするかというのも問題ですし。 -- 前田 修吾 (mailto:shugo@aianet.ne.jp)