From: 7stud -- Date: 2009-09-16T04:26:40+09:00 Subject: Re: .map.with_object(3){|v|v+3} #=> 3 Is this a bug? ErMaker wrote: > At ruby 1.9.2dev (2009-07-18 trunk 24186) [i386-mswin32_90] > > Ruby runs like this. > >>> [1,2,3].map.with_object(3){|v|v+3} > => 3 >>> [1,2,3].each.with_object(3).map{|v|v+3} > => [4, 5, 6] > > > I think that is better to use. > >>> [1,2,3].map.with_object(3){|v|v+3} > => [4, 5, 6] > > Is it a bug? In this line: > [1,2,3].map.with_object(3){|v|v+3} map is called without a block, and ---- ...most built-in iterators return an enumerator when they are called without a block. ---- p. 307 "The Well Grounded Rubyist" Is that true in this case? e = [1, 2, 3].map p e --output:-- # Yep. So what's "in" that enumerator: e.each do |x, y| puts "#{x.inspect} #{y.inspect}" end --output:-- 1 nil 2 nil 3 nil The map enumerator just yields the elements of the array. The next call in the method chain is with_object(): > [1,2,3].map.with_object(3){|v|v+3} and regardless of the iterator that with_object is attached to, when with_object() is called with a block, with_object returns its argument, which in this case is 3. That is why the final result is 3: >>> [1,2,3].map.with_object(3){|v|v+3} > => 3 On the other hand, in this line, >>> [1,2,3].each.with_object(3).map{|v|v+3} > => [4, 5, 6] > with_object is called without a block. And according to the ri information: ------------------------------------------------- Enumerator#with_object e.with_object(obj) {|(*args), memo_obj| ... } e.with_object(obj) From Ruby 1.9.1 ------------------------------------------------------------------------ Iterates the given block for each element with an arbitrary object given, and returns the initially given object. ***If no block is given, returns an enumerator.*** ------------------------ that means with_object returns an enumerator: p [1,2,3].each.with_object(3) --output:-- # What's "in" that enumerator? e = [1,2,3].each.with_object(3) e.each do |x, y| puts "#{x.inspect} #{y.inspect}" end --output:-- 1 3 2 3 3 3 As you can see, the enumerator is returning each element of the array along with with_object's argument: 3. The next call in the method chain is map(): >>> [1,2,3].each.with_object(3).map{|v|v+3} map takes the value(s) it is sent, converts the value(s), then stores the converted value(s) in an array, then the array is returned as the final result of the call to map(): result = [1,2,3].each.with_object(3).map do |v, w| puts "#{v} #{w}" v + 3 end p result --output:-- 1 3 2 3 3 3 [4, 5, 6] That is why you get the result: >>> [1,2,3].each.with_object(3).map{|v|v+3} > => [4, 5, 6] -- Posted via http://www.ruby-forum.com/.