David A. Black wrote:
[...]
>
> I don't have any definitive answers, but I think there's room to clear
> up the ambiguous status of the concept "index" as it is manifested in
> Enumerable.
>

In history, there was a hack submitted to ruby-core which tried to
implement a "block index" which supplied an automatically incrementing
counter to each invocation of *any* iterator.
The discussion turned into one about syntax rather than the concept.
Obviously, when the interpreter is hacked, some syntax might have to be
chosen to expose the index accessor.
I chose for myself (which is the author's prerogative and kind of essential).

So the analogue of this snippet:

   [1,2,3,4,5,6].map_with_index! do |e, ix|
     [2, 5].include?(ix) ? e : e*2
   end

was proposed to be:

   [1,2,3,4,5,6].map! do |e|.ix
     [2, 5].include?(ix) ? e : e*2
   end

In short, #each_with_index is scrapped and you use the standard #each
(or #map or any of the other methods taking a block) with an index/counter
magically available, on demand, within the block.

One could implement a fixed name like '_index_' or one of those Perl
thingies beginning with $ having local scope (as $1, $2 etc.) or any
number of alternatives; the principle is the same.

Two typically useful applications are:

   HUGE_ARRAY.each do |elem|.elnum
     break if $DBG && elnum > 500  # seen enough
     # stuff
   end

   IO.foreach() do |line|.linum
     # stuff where line number is useful (duh!)
   end

One major factor that has bugged me is the lack of symmetry
between #each and #e_w_i which discourages temporary changes.

 h = {:a => 1, :b => 2, :c => 3}
# Current conversion of Hash#each to #each_with_index

 h.each            {|ek, ev|  p [ek  , ev       ]}
 h.each_with_index {|e, idx|  p [e[0], e[1], idx]}
#      ^_________^      ^_^       ^_^  ^^_^  ^_^
#           A            B         C   D C    E

# A.  Change the method name to a much longer one.
# B.  Name the index variable.
# C.  Hash#each gives key and value -- #each_with_index
#     passes these as a two-element array into the first
#     block parameter.  Specify which element.
# D.  The name you chose for the second block parameter of each
#     will, probably, need changing (if you used, say, 'key, val').
# E.  Use the index variable.

Compared to this (with a wishful block index variable):

 h.each  {|ek, ev|     p [ek, ev    ]}
 h.each  {|ek, ev|.xv  p [ek, ev, xv]}
#                 ^_^               ^_
#                  B                 E

Name it ... use it.    (=== *_with_index)

In the interpreter, there'd be an integer in each BLOCK
struct which gets incremented before each iteration.
Not too expensive ?

One final gripe -- if you need a counter inside a block,
it's quicker to maintain your own than use #e_w_i.
(Do reply if this is incorrect.)

#--------------------------------------
require 'benchmark'
include Benchmark

arr = Array.new(100000)

bm(7) do |x|
  x.report('eachA') do
    ixj = 0; arr.each   {|e| ixj += 1}
  end
  x.report('e_w_i') do
    arr.each_with_index {|e, dmy| dmy}
  end
  x.report('eachB') do  # same as 'eachA'
    ixj = 0; arr.each   {|e| ixj += 1}
  end
end
#--------------------------------------


BTW, I had to remove my local patch because it was sooo
usable that it was integrating into my style.


daz