Project

General

Profile

Actions

Bug #12466

closed

Enumerable should yield multiple values when possible

Added by sos4nt (Stefan Schüßler) over 5 years ago. Updated over 5 years ago.

Status:
Rejected
Priority:
Normal
Assignee:
-
Target version:
-
[ruby-core:75871]

Description

Some methods in Enumerable and Array yield arrays instead of multiple values, e.g.:

[1, 2, 3, 4].each_cons(2).peek_values #=> [[1, 2]]

If each_cons would yield multiple values (i.e. yield 1, 2 instead of yield [1, 2]), we could write:

[1, 2, 3, 4].each_cons(2).map(&:quo) #=> [(1/2), (1/3), (1/4)]

But currently, this results in an exception and we have to provide a block to achieve the above:

[1, 2, 3, 4].each_cons(2).map { |a, b| a.quo(b) } #=> [(1/2), (2/3), (3/4)]

No big deal, but it looks a bit cumbersome (in Ruby terms) and I don't see how the current behavior is preferable.

Another example is reverse_each which cripples yielded values:

def each_two_values
  return enum_for(__method__) unless block_given?
  yield 1, 2
  yield 2, 3
  yield 3, 4
end

each_cons_values.map(&:quo) #=> [(1/2), (2/3), (3/4)]

each_cons_values.reverse_each.map(&:quo) #=> NoMethodError: undefined method `quo' for [3, 4]:Array

Of course, I can easily provide my own implementation:

module Enumerable
  def my_reverse_each
    return enum_for(__method__) unless block_given?
    map { |*values| values }.reverse.each { |values| yield *values }
  end
end

each_cons_values.my_reverse_each.map(&:quo) #=> [(3/4), (2/3), (1/2)]

But shouldn't this be the default behavior?

If an array is actually needed (instead of multiple values), there's Enumerable#each_entry which performs the conversion.

BTW, other methods do yield multiple values:

%w(a b c).each.with_index(1).peek_values #=> ["a", 1]
Actions

Also available in: Atom PDF