On Mon, Sep 22, 2008 at 07:42:24PM +0900, Brian Candler wrote:
> Sylvain Joyeux wrote:
> > Nope. each { } needs one new scope for each iteration
> 
> By 'scope' do you mean 'stack frame'?
> creates three objects which need to be garbage-collected, and therefore 
> that the loop
> 
>   for i in (1..3)
>     foo(i)
>   end
> 
> also creates three garbage objects.
Yes. Except that

  collection.each do |obj|
    foo(obj)
  end

creates twice the amount of

  for obj in collection
    foo(obj)
  end

which is what we are trying to compare here.

> I don't believe that's the case. I would imagine that the stack runs as, 
> well, a stack. (It's not quite that simple when you get into creating 
> closures of course, but if you call a closure 1000 times, you're not 
> creating 1000 new closures)
> 
> Am I missing something?
Yes. I don't know for the current version of the 1.9 VM, but currently
the interpreter does not 'reuse' stack frames, and therefore you *do*
create one object per new scope. To cut down the discussion,
ObjectSpace#each_object does *not* give you those, so you can't count
them with it.

> Finally, I tried some simple measurements.
> 
> $ time ruby -e 'a = (1..5_000_000).to_a; a.each { :dummy }'
> $ time ruby -e 'a = (1..5_000_000).to_a; for i in a; :dummy; end'
> 
> Under ruby 1.8.6p114, I find the first is about 5% faster.
> 
> Under ruby 1.8.4 (Ubuntu Dapper), I find the first is about 25% faster.
Interesting. I have the same results, but (on my machine) the following
is even slower:
 $ time ruby -e 'a = (1..5_000_000).to_a; a.each { |i| :dummy }'