From: Koji Arai Date: 2003-08-25T06:51:19+09:00 Subject: [ruby-dev:21256] Re: [ruby-cvs] ruby: * enum.c (inject_i):userb_yield_values. 新井です。 In message "[ruby-dev:21253] Re: [ruby-cvs] ruby: * enum.c (inject_i):userb_yield_values." on Sun, 24 Aug 2003 02:21:15 +0900, matz@ruby-lang.org (Yukihiro Matsumoto) wrote: > まつもと ゆきひろです > |簡単に言うとscanがブロックに何を渡すべきかです。 > |私の意見は > | > | * 1個の配列([$1,$2..]) > | * マッチした括弧の数だけの値(*[$1,$2..]) > | > |のいずれかが望ましいのではないか、です。1.8では上記の二つは > |違う意味を持っています。 > | > |今、CVSでは後者になっています。 > > しかし、考えてみるとscanは > > * 括弧がある時には配列 > * 括弧がない時には文字列 > > を渡すと言う仕様になっているので、やはり前者の方が望ましいよ > うですね。この修正は元に戻します。この修正の発想の元はscanf > だったのですが、括弧がない場合に相当するものがないscanfとは > 違う発想が必要でした。 > > scanfの方はscanに合わせたいそうですので、結局1.8.0の仕様があ > るべき仕様という結論になりそうです。難しいものだな。 うむむ。CVS「後者」版を試してみましたが、これは悩ましいです ね。いずれにしても非互換になるわけだ。 "a".scan(/(.)/) {|*a| p a} => ruby 1.6.8 (2003-08-03) [i586-linux] ["a"] => ruby 1.8.0 (2003-08-04) [i586-linux] <- 前者の非互換 [["a"]] => ruby 1.8.0 (2003-08-24) [i586-linux] ["a"] "a".scan(/(.)/) {|a| p a} => ruby 1.6.8 (2003-08-03) [i586-linux] ["a"] => ruby 1.8.0 (2003-08-04) [i586-linux] ["a"] => ruby 1.8.0 (2003-08-24) [i586-linux] "a" <- 後者の非互換 この非互換への対処がいずれにしても必要になるわけですが、イテ レータの実装側は複数のパラメータを渡す可能性のあるイテレータ を実装する場合、二つの選択肢があります。 (1) yield ary (2) yield *ary (あるいは yield a,b,...) (1) は、ブロックを書く側がパラメータを ary の要素数あるいは 一変数(var)で受けなければならないという制約があります。そう しないと(*var で受けると)ary が一要素のとき var は配列にな りません(配列の配列になります)。 (2) は、ブロックを書く側がパラメータを ary の要素数あるいは *var で受けなければならないという制約があります。そうしない と(var で受けると)ary が一要素のとき var は配列になりません。 なんと、イテレータ利用者にとってはどちらもあまり変わらないの ですね。イテレータのあるべき仕様(配列を渡すか多値を渡すか)に よってどちらが自然かを選ばなくてはいけません。 考えられる判断材料をいろいろと検討したのですが、決定的な一般 則を思い付くことができませんでした。 で、私見ですがなんとなく scan の場合は (2)の方が驚きがすくな い気はします。ブロック利用者は一つの配列が欲しいのではなく、 複数の部分配列が欲しい(多値が基本)だと思うのです。 多値が基本で単値(配列)が欲しい場合は *var で受けなさいという のは 1.6 から変わらない考え方だと思うからですが。 # 多値が基本かどうかは怪しいですが。 が、これはかなり感覚的な(しかも即席な)意見ですのであまりアテ になりませんねえ。 # 実は、どちらも変わらないというのが真実なのではなかろうかと # 思っているのですが、scanf の際に [["a"]] という結果は驚き # が大きかったのは事実でして・・・ ところで上記とは逆に元に戻すこと自体は賛成です。中途半端な変 更は混乱を来すので。もう少し様子を見た方が良いでしょうね。 -- 新井康司 (Koji Arai)