#map and map_with_index are identical except that the latter also yields an index counter.
But this counter is entirely optional and can be omitted from the block. It's possible to call #map_with_index with exactly the same signature as #map.
["foo", "bar"].map_with_index do |e|
e.upcase
end # => ["FOO", "BAR"]
["foo", "bar"].map do |e|
e.upcase
end # => ["FOO", "BAR"]
The implementation of both methods is also pretty much identical, in Enumerable as well as in any including type.
Of course, map_with_index has a counter and yields its value. But LLVM optimization happily removes it when unused.
So I think it makes sense to implement Enumerable#map by delegating to #map_with_index. This embodies the close connection between these two methods.
As a result, including types only need to override #map_with_index with a custom implementation and #map will follow suit.
Including types may still override #map with a custom implementation, of course.
#map
andmap_with_index
are identical except that the latter also yields an index counter.But this counter is entirely optional and can be omitted from the block. It's possible to call
#map_with_index
with exactly the same signature as#map
.The implementation of both methods is also pretty much identical, in
Enumerable
as well as in any including type. Of course,map_with_index
has a counter and yields its value. But LLVM optimization happily removes it when unused.So I think it makes sense to implement
Enumerable#map
by delegating to#map_with_index
. This embodies the close connection between these two methods. As a result, including types only need to override#map_with_index
with a custom implementation and#map
will follow suit. Including types may still override#map
with a custom implementation, of course.