RCR enumerable extra into core

On Tue, Nov 10, 2009 at 10:47 AM, Brian C. [email protected]
wrote:

other Enumerators. When you want a real array, then add .to_a to the
end.

And you base this ultimate conclusion on what?

Prior to Ruby 1.9, most Enumerable methods required that a block be
passed and would raise an error if not. There are few, such as to_a
which did not.

If you wanted an enumerator you needed to do something like

(1…100).enum_for(:inject, 0)

In Ruby 1.9 the enumerable methods got a little more relaxed, they
work as before if a block IS given, and if not they return an
enumerator instead.

So, my ultimate conclusion is that enumerable methods should almost
always use a block passed as an argument to do whatever they do, and
for Ruby 1.9 at least return an enumerator if a block is not passed
which will do whatever the enumerable itself would do with a block.

And a Ruby method can’t distinguish wheter it was called with syntax
like

some_method { # some block
}

or

some_method(&something_which_understands_to_proc)

In both cases block_given? inside the method invocation will return
true.

Now as I understand it, the proposal would be to make

list.map(:method)

do the same thing as

list.map(&:method)

One problem with this is what to do with something like

list.inject(:initial_value)

Where instead of a proc, :initial_value represents the initial value
for an enumerator. I would argue that only the caller knows which one
he/she wants.

That “&” is pretty important in distinguishing these two cases.


Rick DeNatale

Blog: http://talklikeaduck.denhaven2.com/
Twitter: http://twitter.com/RickDeNatale
WWR: http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn: http://www.linkedin.com/in/rickdenatale

Hi,

I’m quite conservative or maybe ‘wise’, seeing this discussion.

In fact, using arr.map(:method, arg1 … ) is too confusing to me
While the &:method notation is clear, and not that ugly.

And I think it has to be a separation between blocks and arguments;
block is
another “kind” of argument.
That’s why I think we should keep the &:method, and forget about
:method.
Note also that is not a common use of &:method, because you often need
to do
ore than one thing with the element. eg:
[1,15,3].map { |e| e.to_s.length }

P.S.:
Why &:method is faster ? (Bad, I wanted to argue &:method is slower but
I
can’t …)
(requiring and including Benchmark)
irb(main):008:0> realtime { (1…1000000).to_a.map &:to_s }
=> 0.38111090660095215
irb(main):009:0> realtime { (1…1000000).to_a.map { |e| e.to_s } }
=> 0.445728063583374

2009/11/11 David A. Black [email protected]

This reminds me of the early 1.9.0 thing, where you could do:

array = [1,2,3,4]
enum = array.enum_for(:map, &lambda {|x| x * x })

enum.next # 1
enum.next # 4

It is surprising that currently it appears to ignore the given block.

b = File.open(‘file’, ‘r’).lines{|line| lines * 2}
b.next
=> “xx\n”

b.next
=> “xx\n”

Is this expected?
-r

Hi –

On Wed, 11 Nov 2009, Brian C. wrote:

one logical conclusion (or extreme viewpoint) is that you could always
return an Enumerator, even for

map { |x| x*x }

I wasn’t saying that Ruby does anything like this, and it’s a tangent to
the original thrust of map(:foo).

This reminds me of the early 1.9.0 thing, where you could do:

array = [1,2,3,4]
enum = array.enum_for(:map, &lambda {|x| x * x })

enum.next # 1
enum.next # 4

etc. (That’s ruby 1.9.0 (2008-03-01 revision 15660)
[i686-darwin9.2.0].) To be honest, when that disappeared, it seemed to
me to do away with a great deal of the usefulness of enumerators.
Given that you can no longer attach a block to an enumerator when you
create the enumerator, I don’t think there are any actual use cases
for the fact that map returns an enumerator (or at least very, very
few). You can’t do this, for example (following the above example):

enum.select {|x| x > 1 } # [4, 9, 16]

David


The Ruby training with D. Black, G. Brown, J.McAnally
Compleat Jan 22-23, 2010, Tampa, FL
Rubyist http://www.thecompleatrubyist.com

David A. Black/Ruby Power and Light, LLC (http://www.rubypal.com)

This reminds me of the early 1.9.0 thing, where you could do:

array = [1,2,3,4]
enum = array.enum_for(:map, &lambda {|x| x * x })

enum.next # 1
enum.next # 4

Appears somewhat possible…

class Enumerator
def filter(&blk)
self.class.new do |y|
each do |*input|
out = blk.call(*input)
y << out
# or y << out if out
end
end
end
end

array = [1,2,3,4]
enum = array.enum_for(:map).filter {|x| x * x }
enum.next
=> 1
enum.next
=> 4

enum.select {|x| x > 1 } # [4, 9, 16]
=> [4, 9, 16]

[Thanks to Brian C. for the snippet–though perhaps it could be
improved…]

This should be the default, though–I don’t know why blocks are ignored
currently…

-r

http://www.ruby-forum.com/topic/169844#new