From: EGUCHI Osamu Date: 1999-10-27T15:47:22+09:00 Subject: [ruby-dev:8127] Re: [ruby-list:17940] Enumerable#collect えぐち@エスアンドイー です。 >>> In message [ruby-dev:8123] Re: [ruby-list:17940] Enumerable#collect On Wed, 27 Oct 1999 00:29:28 +0900, Takashi Ikeda said: cercine> 池田孝志です。 cercine> cercine> 僕の言った事に対してだけ返答します。 cercine> cercine> EGUCHI Osamu writes: cercine> cercine> > えぐち@エスアンドイー です。 ... cercine> > この、 『Array#to_a にもdup が要る様な気がします。』は、 cercine> > cercine> > % ruby -v cercine> > ruby 1.4.2 (1999-09-18) [i386-freebsd3.3] cercine> > % ruby -e 'a=[];b=a.to_a;p a.equal? b' cercine> > →true cercine> > % cercine> > cercine> > の様な状況の事を言っています。 cercine> > cercine> > あと、大概の to_a / collect は新しい Array に push しているので、 cercine> > dup は不要と言うのは同感ですが、 cercine> > cercine> > return self.dup if self.is_a? Array cercine> > cercine> > では、「大概の」ではなく、Array#collect を特別扱いしています。 cercine> cercine> 大体、[ruby-dev:8090]自体バグっていることはともかく、これを cercine> 出した段階では、Enumerable#to_aを知らなかったのであえてこう cercine> していました。意図は汲んでもらえるとして、 了解です。 cercine> > まぁ、効率にしか影響しないし、必ずしも速くなる場合だけでもなようです。 cercine> cercine> ですが、Array#collectをArray#to_aのdupを取ったものの代わりと cercine> して利用するには、[ruby-dev:8090]時点の僕には酷でした。 cercine> cercine> % ruby -v cercine> ruby 1.4.2 (1999-09-18) [i586-linux] cercine> % ruby -e ' cercine> a = Array.new(1000_000) cercine> cercine> GC.start cercine> t = Time.now cercine> a.collect {|e| e } cercine> p Time.now - t cercine> cercine> GC.start cercine> t = Time.now cercine> a.to_a cercine> p Time.now - t cercine> ' cercine> 279.01583 cercine> 8.6e-05 cercine> cercine> [ruby-dev:8090]はEnumerable#to_aを知らない段階で作ったので、 cercine> [ruby-dev:8090]のcollectがEnumerable#to_aをdupしたものと同じ cercine> 結果を出すようにしか考えていません。よってレシーバにArrayが cercine> やってきたときには、yieldのぶん速くした方がよいのではないか cercine> という提案でした。 なるほど、、 cercine> 判定でちょっと遅くなるくらいなら、相当遅くなるのを回避した方 cercine> が良いか、と思ったので。 cercine> もちろん、これがあまり要らないと僕が感じている事は、 cercine> [ruby-dev:8090]に書いたとおりです。 Array#to_a が self を返すを是とするので、 この Array をレシーバとした場合の特別扱いは、 不要と結論づけてよいですね。 cercine> Array#to_aでは(ソースとしては)レシーバを返すという仕様がある、 cercine> という点も知らなかったので、えぐちさんが入る前の cercine> [ruby-dev:8098]で僕は[ruby-dev:8090]のcollectを cercine> Enumerable#to_aと等価と考えていました。今のto_aから得たオブ cercine> ジェクトを[ruby-dev:8090]のcollect として動作させるには、dup cercine> しないといけないようです。[ruby-dev:8090]の*1つ目の*collect cercine> には、やはりこのような二度手間はさせたくありません。 cercine> # もちろん、僕はArray#to_aをdupさせたいと思ったことは*今も* cercine> # ありません。 別スレッドで、 bang(名前の終りが '!') なメソッドとそれと対になる bang でないメソッドがある場合は、 bang な方はレシーバを返し、 bang でない方は新しいインスタンスを返す。 という事に付いての議論があったので、dup する/しないに ある種のこだわりを、持っていました。 それで dup はそれ自体の実行コストはともかく、GC にやさしくないので、 深刻な問題を起こさない限り、レシーバを返すのが良いかな、、 と今は思っています。 えぐち