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