Array#index block and rdetect

trans. (T. Onoma) wrote:

All enumerable objects don't neccessarilly have a meaningful concept of
an index. Eg. sets, multisets. Enumerable and Indexable are two
different things, though Indexable extends Enumerable.

  Main Entry: enu·mer·a·ble
  Pronunciation: i-'n(y)üm-r&-b&l, -'n(y)ü-m&-
  Function: adjective
  : DENUMERABLE

  Main Entry: de·nu·mer·a·ble
  Pronunciation: di-'n(y)ü-m&-r&-b&l
  Function: adjective
  : capable of being put into one-to-one correspondence
    with the positive integers

So "index" must mean this corresponding integer. I would argue that sets and hashes are not technically enumerable, because they're elements can not be accessed as a _function_ of the index, i.e. one-to-one correspondence.

Perhaps separate Collectable and Indexable modules would be preferable.

hmm, I guess in the current context I think of enumerable as meaning iteratable, i.e. you can start at one element and "move" through the entire collection, visiting each element only once while visiting every element of the collection. This implies nothing about the ordering of the list; subsequent enumerations could (but probably wouldn't) produce a different ordering. (i.e. a file entry may appear as the first element through one enumeration, but as the third entry during another enumeration.)

Indexable, OTOH, would be the property which allows accessing a particular element by positional or named access.

Everything that is indexable is also enumarable, but not vice versa.

Sets, multisets, directory listings are enumerable, but not indexable.

Arrays, hashes, are both enumerable and indexable.

Enumerable is probably not the right word, but it is what is currently being used for the concept of iteratable.

Randy.

···

On Monday 20 September 2004 09:52 am, Randy W. Sims wrote:

Hi --

> All enumerable objects don't neccessarilly have a meaningful concept of
> an index. Eg. sets, multisets. Enumerable and Indexable are two
> different things, though Indexable extends Enumerable.

  Main Entry: enu·mer·a·ble
  Pronunciation: i-'n(y)üm-r&-b&l, -'n(y)ü-m&-
  Function: adjective
  : DENUMERABLE

  Main Entry: de·nu·mer·a·ble
  Pronunciation: di-'n(y)ü-m&-r&-b&l
  Function: adjective
  : capable of being put into one-to-one correspondence
    with the positive integers

So "index" must mean this corresponding integer. I would argue that sets and
hashes are not technically enumerable, because they're elements can not be
accessed as a _function_ of the index, i.e. one-to-one correspondence.

But "being put into one-to-one correspondence" can be done externally,
and you can definitely do it with a hash. The question is: how much
knowledge of this should the hash itself have? My answer is: none. A
hash has no reason to know about or be responsible providing the list
of integers against which it can be enumerated. They have no
connection to the hash or its elements themselves.

David

···

On Mon, 20 Sep 2004, trans. (T. Onoma) wrote:

On Monday 20 September 2004 09:52 am, Randy W. Sims wrote:

--
David A. Black
dblack@wobblini.net

Hi,

···

In message "Re: Array#index block and rdetect" on Mon, 20 Sep 2004 19:39:49 +0900, "David A. Black" <dblack@wobblini.net> writes:

Question: if "index" is a basic Enumerable thing, why is there no
Enumerable#each_index? (My preference would be to push
#each_with_index down to the individual classes too; but in any case,
I'm curious about it.)

"index" in "each_with_index" is a loop counter. Perhaps wrong choice
of the word. It happen to be same index in Arrays.

              matz.

Just for what it's worth, this is a mathematical notion the closest
everyday word for which is "countable". 'Capable of being put into
one-to-one correspondence with the positive integers' merely means you
can count the elements of the set one by one, not that there is any
preferred ordering of the elements. (Although establishing such a
preferred ordering is often the method used to prove that a set is
denumerable, e.g. the rationals.)

martin

···

"trans. (T. Onoma)" <transami@runbox.com> wrote:

  Main Entry: enu·mer·a·ble
  Pronunciation: i-'n(y)üm-r&-b&l, -'n(y)ü-m&-
  Function: adjective
  : DENUMERABLE

  Main Entry: de·nu·mer·a·ble
  Pronunciation: di-'n(y)ü-m&-r&-b&l
  Function: adjective
  : capable of being put into one-to-one correspondence
    with the positive integers

So "index" must mean this corresponding integer. I would argue that sets and
hashes are not technically enumerable, because they're elements can not be
accessed as a _function_ of the index, i.e. one-to-one correspondence.

"David A. Black" <dblack@wobblini.net> schrieb im Newsbeitrag
news:Pine.LNX.4.44.0409200324260.11614-100000@wobblini...

Hi --

>
> "Yukihiro Matsumoto" <matz@ruby-lang.org> schrieb im Newsbeitrag
> news:1095650370.096071.21408.nullmailer@x31.priv.netlab.jp...
> > Hi,
> >
> >
> > >> * Enumerable#each_index should be removed (yes/no)
> > >
> > >There is no Enumerable#each_index -- nothing to remove.
> >
> > I meant each_with_index.
> >
> > >> * How about other enumerable classes?
> > >
> > >I think the idea of every enumerable class having an "index",

defined

> > >as part of that class, is possibly useful.
>
> Sorry, David, I stongly disagree: IMHO an index does only make sense

in a

> class that maintains a certain order (such as Array). A Hash does not
> have a particular order and thus Enumerable#each_with_index is the
> appropriate thing; here the index is valid just for the current

iteration

> and can be used for printing or whatever. But I would not want to add

an

> index to a Hash.
>
> Or did you mean to use the hash key as index?

Yes. I certainly didn't mean numerical indexes for hashes; that's the
whole problem (well, part of the problem) with Hash#each_with_index in
the first place. Also, by "defined as part of that class", I meant
defined according to the needs of that class, so that for arrays it
would be integers, for hashes the keys, etc.

Ok, I see. I wouldn't change the behavior of #each_with_index since that
is likely to break a lot code. Read on for my suggestion.

> That would be a different
> story... While that would make sense for Array and Hash I think there

are

> a lot Enumerables out there that do not correspond easily to

associative

> storage, for example a Enumerable that emits arbitrary many random

numbers

> in its #each method.

That problem is already there, in the sense that such an object
already has an #each_with_index method. I'm trying to make sense of
the notion of "index" as part of Enumerable, though it's quite
possible that *not* having it be part of Enumerable would be better --
and then classes could either define index-related methods or not.
(That's what I meant originally about leaving #each_with_index up to
the individual classes, like #each_index.)

Well, I think the main problem here is confusion of two different things:
numerical indexing (I'll use the term "index" for this) and lookup keys
(called "keys" hereafter).

In my understanding Enumerable#each_with_index just goes through the
enumerable and counts an index which can be used for printing or counting
or whatever. So I would not change this method. These indexes are purely
per enumeration and can change for any number of reasons.

Additionally we should have Array#each_with_key and Hash#each_with_key and
AnyOtherLookupCollection#each_with_key (or call it #each_pair) that yield
key, value pairs. In the case of an Array the keys happen to be identical
with the indexes of a forward iteration but in case of a Hash keys are
hash keys and thus different from indexes.

I think the problem stems from the fact that we want to handle indexes and
keys with a single set of methods wile in fact these are different things
that only occasionally overlap.

> > For hashes it could be the
> > >keys; for arrays, the integer index; for files, the line number.

In

> > >some cases (like index/key for hashes), it might be redundant. But

it

> > >might open up some good possibilities.
> >
> > The most consistent (but incompatible) change would be:
> >
> > * leave Enumerable#each_with_index unchanged.
> > * make Hash#each as alias of Hash#each_value
> > * redefine Hash#each_with_index as alias of Hash#each_pair
> >
> > But this change may break many programs.
>
> Yeah, that's true. What about a method in Hash that changes method
> behavior to the array compatible style? That way no old code is

broken

> and you can purposely change a Hash's look if you need to make sure

that

> this Hash can be interchangeably used with an Array.

It's called #to_a :slight_smile: I think that's better than having a switch that
changes behavior. We're going to start hearing a lot of "for
historical reasons..." and "glued on as an afterthought..." otherwise
:slight_smile:

Yeah, you're right.

Kind regards

    robert

···

On Mon, 20 Sep 2004, Robert Klemme wrote:
> > In message "Re: Array#index block and rdetect" > > > on Mon, 20 Sep 2004 11:12:12 +0900, "David A. Black" > > <dblack@wobblini.net> writes:

"Randy W. Sims" <ml-ruby@thepierianspring.org> schrieb im Newsbeitrag
news:414EEA6D.3050105@thepierianspring.org...

trans. (T. Onoma) wrote:
>
>>All enumerable objects don't neccessarilly have a meaningful concept

of

>>an index. Eg. sets, multisets. Enumerable and Indexable are two
>>different things, though Indexable extends Enumerable.
>
>
> Main Entry: enu·mer·a·ble
> Pronunciation: i-'n(y)üm-r&-b&l, -'n(y)ü-m&-
> Function: adjective
> : DENUMERABLE
>
> Main Entry: de·nu·mer·a·ble
> Pronunciation: di-'n(y)ü-m&-r&-b&l
> Function: adjective
> : capable of being put into one-to-one correspondence
> with the positive integers
>
> So "index" must mean this corresponding integer. I would argue that

sets and

> hashes are not technically enumerable, because they're elements can

not be

> accessed as a _function_ of the index, i.e. one-to-one correspondence.

No. You *can* enumerate all elements (or all pairs) in a Hash.

> Perhaps separate Collectable and Indexable modules would be

preferable.

hmm, I guess in the current context I think of enumerable as meaning
iteratable, i.e. you can start at one element and "move" through the
entire collection, visiting each element only once while visiting every
element of the collection. This implies nothing about the ordering of
the list; subsequent enumerations could (but probably wouldn't) produce
a different ordering. (i.e. a file entry may appear as the first element
through one enumeration, but as the third entry during another

enumeration.)

Indexable, OTOH, would be the property which allows accessing a
particular element by positional or named access.

Totally agree up to here.

Everything that is indexable is also enumarable, but not vice versa.

I think those concepts are orthogonal. As an example, you can view the
sin function as indexable but I doubt you'd call it enumerable (although
technically you could do that becaus Float numbers are really rational
numbers and not real numbers).

Sets, multisets, directory listings are enumerable, but not indexable.

I agree with sets and multi sets, but one could argue that dir listings
have an order and thus can be indexed.

Arrays, hashes, are both enumerable and indexable.

Si.

Enumerable is probably not the right word, but it is what is currently
being used for the concept of iteratable.

I find it perfectly suited.

Kind regards

    robert

···

> On Monday 20 September 2004 09:52 am, Randy W. Sims wrote:

I Agree.

···

On Monday 20 September 2004 10:56 am, David A. Black wrote:

But "being put into one-to-one correspondence" can be done externally,
and you can definitely do it with a hash. The question is: how much
knowledge of this should the hash itself have? My answer is: none. A
hash has no reason to know about or be responsible providing the list
of integers against which it can be enumerated. They have no
connection to the hash or its elements themselves.

--
( o _ カラチ
// trans.
/ \ transami@runbox.com

I don't give a damn for a man that can only spell a word one way.
-Mark Twain

I've never cared one way or the other about Hash#each_with_index.
It's pretty useless as the numbers tell you nothing meaningful.

When I want to iterate a hash completely, I use

  hash.each do |key, value| ... end

and that suits me fine. But even that is rare because of the
meaningless output order. So it's usually more like:

  hash.keys.sort.each do |key|
    value = hash[key]
    ...
  end

or

   hash.sort_by { |key, value| key }.each do |key, value|
     ...
   end

I don't see a real need for any methods to change. Hash is clearly an
enumerable. I see it as a collection of pairs/associations; that's
why I use Hash#each instead of the equivalent but redundant
Hash#each_pair.

Hash#each_with_index is useless, but I don't find it misleading. The
very first time I ran 'ri Hash', I was able to work out what's going
on. When you see Hash#each_pair and Hash#each_with_index, you know
that the "index" doesn't refer to keys.

If you defined Hash#each_with_index specially, instead of relying on
the Enumerable implementation, I guess this would be sensible:

  class Hash
    def each_with_index
      each_pair do |key, value|
        yield(value, key)
      end
    end
  end

Cheers,
Gavin

···

On Tuesday, September 21, 2004, 1:30:12 AM, Yukihiro wrote:

>Question: if "index" is a basic Enumerable thing, why is there no
>Enumerable#each_index? (My preference would be to push
>#each_with_index down to the individual classes too; but in any case,
>I'm curious about it.)

"index" in "each_with_index" is a loop counter. Perhaps wrong choice
of the word. It happen to be same index in Arrays.

Hi --

> > Or did you mean to use the hash key as index?
>
> Yes. I certainly didn't mean numerical indexes for hashes; that's the
> whole problem (well, part of the problem) with Hash#each_with_index in
> the first place. Also, by "defined as part of that class", I meant
> defined according to the needs of that class, so that for arrays it
> would be integers, for hashes the keys, etc.

Ok, I see. I wouldn't change the behavior of #each_with_index since that
is likely to break a lot code. Read on for my suggestion.

I honestly doubt it would break much code. I have never seen
Hash#each_with_index used.

> > That would be a different
> > story... While that would make sense for Array and Hash I think there
are
> > a lot Enumerables out there that do not correspond easily to
associative
> > storage, for example a Enumerable that emits arbitrary many random
numbers
> > in its #each method.
>
> That problem is already there, in the sense that such an object
> already has an #each_with_index method. I'm trying to make sense of
> the notion of "index" as part of Enumerable, though it's quite
> possible that *not* having it be part of Enumerable would be better --
> and then classes could either define index-related methods or not.
> (That's what I meant originally about leaving #each_with_index up to
> the individual classes, like #each_index.)

Well, I think the main problem here is confusion of two different things:
numerical indexing (I'll use the term "index" for this) and lookup keys
(called "keys" hereafter).

In my understanding Enumerable#each_with_index just goes through the
enumerable and counts an index which can be used for printing or counting
or whatever. So I would not change this method. These indexes are purely
per enumeration and can change for any number of reasons.

I have the same understanding, and that's why I *would* change this
(frequently useless) method :slight_smile: See below....

Additionally we should have Array#each_with_key and Hash#each_with_key and
AnyOtherLookupCollection#each_with_key (or call it #each_pair) that yield
key, value pairs. In the case of an Array the keys happen to be identical
with the indexes of a forward iteration but in case of a Hash keys are
hash keys and thus different from indexes.

I think the problem stems from the fact that we want to handle indexes and
keys with a single set of methods wile in fact these are different things
that only occasionally overlap.

Actually my suggestion earlier was to detach the concept of "index"
from Enumerable so that each enumerable class could define it as it
wanted to. That's why I'd like to push #each_with_index out of
Enumerable. It's the only "index" method in Enumerable, and I think
it can lead to too specific a concept of indexing for classes like
Hash where numerical indexes are essentially meaningless. (I guess
this might change if hashes become ordered....)

I would prefer, in other words, for key and index to overlap in Hashes
as well as Arrays. I just don't see enough advantage in having this
semi-magic #each_with_index at the level of Enumerable (semi-magic in
the sense that it does a kind of implicit to_a).

Or, if index always means a (to_a-based) numerical index, then
#each_index should be in Enumerable, and not left to the individual
classes. Then it would be clearer that index == 0-origin, possibly
meaningless (for unordered collections), numerical index. Classes
that specialized from this could either re-use the name index (for
example, a 1-origin collection), or introduce a set of methods with a
new name/concept (like key).

David

···

On Mon, 20 Sep 2004, Robert Klemme wrote:

--
David A. Black
dblack@wobblini.net

Robert Klemme wrote:

That problem is already there, in the sense that such an object
already has an #each_with_index method. I'm trying to make sense of
the notion of "index" as part of Enumerable, though it's quite
possible that *not* having it be part of Enumerable would be better --
and then classes could either define index-related methods or not.
(That's what I meant originally about leaving #each_with_index up to
the individual classes, like #each_index.)

Well, I think the main problem here is confusion of two different things:
numerical indexing (I'll use the term "index" for this) and lookup keys
(called "keys" hereafter).

Let me propose yet another alternative. (More general than my last one.) Let .each yield(item, *more) and make all methods provided by Enumerable pass on *more.

This would allow Hash#each to do this:

   class Hash
     def each
       loop over key => value pairs do
         yield(value, key)
       end
     end

     include Enumerable
   end

   hash = {1 => 2, 3 => 4}
   hash.each { |value,| puts value }
   hash.map { |value, key| [key, value] } # from hash to assoc array
   hash.inject(0) { |state, value, key| state + [value, key].hash }

and Array to do this:

   class Array
     def each
       0.upto(size - 1) do |index|
         yield(self[index], index)
       end
     end

     include Enumerable
   end

   array = ["hello", "nice", "world"]
   array.find_all { |item, index| index > 0 }
   array.each { |item,| p item }

I still dislike the trailing comma that is needed if you don't want to use the extra information. This could be fixed by doing an arity check on blocks and not yielding the extra information when the block only wants a single argument.

Also note that this means we won't have to deal with all the #map_with_index and so on trouble any more, Hash wouldn't need to virtually overwrite any method provided by Enumerable and that we can even easily make Enumerables that yield other information. (Is anybody able to think about a good use for that feature?)

The biggest problem is that backwards compatibility would be severely broken if this were to be introduced. Maybe even too severely for Rite.

Kind regards
    robert

More regards,
Florian Gross

That's an interesting perspective. So you're saying index is just a "helper"
counter. These being equivalent:

  enumobj.each_with_index {|a,i| ... }

  enumobj.each {|a| i=(i||-1)+1; ... }

Maybe so, although I'd prefer #each_with_counter, in that case. Think of an
"index" in the back of a book.

A bit of an aside, I've been thinking about synchronizing enumerable objects.
For the sake of discussion lets say *=* means synchronize. So,

  ([1,2,3]*=*[7,8,9]).each {|a,b| puts "#{a},#{b}" }

  => 1,7
     2,8
     3,9

Then "indexing" can also be done with

  (enumobj*=*(0..enumobj.length-1)).each{|a,i|}

If a method #range is defined, this can be simplified too

  (enumobj*=*enumobj.range).each{|a,i|}

Is there a good way to do this?

T.

···

On Monday 20 September 2004 08:54 am, Robert Klemme wrote:

In my understanding Enumerable#each_with_index just goes through the
enumerable and counts an index which can be used for printing or counting
or whatever. So I would not change this method. These indexes are purely
per enumeration and can change for any number of reasons.

--
( o _ カラチ
// trans.
/ \ transami@runbox.com

I don't give a damn for a man that can only spell a word one way.
-Mark Twain

Well, there is a a subtle distinction that can be drawn: by "enumerating a
hash", it undergoes a transformation and it isn't really a hash any more
--order has imposed upon it, and hashes have no order. Hence David's sense of
a "magic" to_a. Granted this is quite minor.

So, I agree with you. I just think the word 'index' is the wrong word, and
source of much the "confusion". If it's really needed the word 'enumerator'
would be better.

  each_with_enumerator{|a,e| ... }

(Or perhaps just 'enum' for short)

And then each_with_index can be defined as has been suggested, per class. For
Array it would just be an alias to the above I suppose.

T.

···

On Monday 20 September 2004 10:59 am, Robert Klemme wrote:

No. You *can* enumerate all elements (or all pairs) in a Hash.

--
( o _ カラチ
// trans.
/ \ transami@runbox.com

I don't give a damn for a man that can only spell a word one way.
-Mark Twain

Hi --

Let me propose yet another alternative. (More general than my last one.)
Let .each yield(item, *more) and make all methods provided by Enumerable
pass on *more.

This would allow Hash#each to do this:

   class Hash
     def each
       loop over key => value pairs do
         yield(value, key)
       end
     end

     include Enumerable
   end

   hash = {1 => 2, 3 => 4}
   hash.each { |value,| puts value }
   hash.map { |value, key| [key, value] } # from hash to assoc array
   hash.inject(0) { |state, value, key| state + [value, key].hash }

and Array to do this:

   class Array
     def each
       0.upto(size - 1) do |index|
         yield(self[index], index)
       end
     end

     include Enumerable
   end

   array = ["hello", "nice", "world"]
   array.find_all { |item, index| index > 0 }
   array.each { |item,| p item }

I still dislike the trailing comma that is needed if you don't want to
use the extra information. This could be fixed by doing an arity check
on blocks and not yielding the extra information when the block only
wants a single argument.

The trailing comma, and the sense that it's impossible to just iterate
purely over the elements, is bad -- but other than that, I think I
like the idea.

Also note that this means we won't have to deal with all the
#map_with_index and so on trouble any more, Hash wouldn't need to
virtually overwrite any method provided by Enumerable and that we can
even easily make Enumerables that yield other information. (Is anybody
able to think about a good use for that feature?)

You could send a "last item" flag (Hal, are you reading? :slight_smile: Also you
could have 1-originating indices.

David

···

On Mon, 20 Sep 2004, Florian Gross wrote:

--
David A. Black
dblack@wobblini.net

"trans. (T. Onoma)" <transami@runbox.com> schrieb im Newsbeitrag
news:200409200947.47623.transami@runbox.com...

> In my understanding Enumerable#each_with_index just goes through the
> enumerable and counts an index which can be used for printing or

counting

> or whatever. So I would not change this method. These indexes are

purely

> per enumeration and can change for any number of reasons.

That's an interesting perspective. So you're saying index is just a

"helper"

counter. These being equivalent:

  enumobj.each_with_index {|a,i| ... }

  enumobj.each {|a| i=(i||-1)+1; ... }

I'd say rather

i=-1
enumobj.each {|a| i+=1; ... }

Reason: scoping rules:

%w{aa bb cc}.each {|a| i=(i||-1)+1; p [a,i]}

["aa", 0]
["bb", 0]
["cc", 0]
=> ["aa", "bb", "cc"]

Maybe so, although I'd prefer #each_with_counter, in that case. Think of

an

"index" in the back of a book.

Well, there might be better names, but the current name happens to be the
one it is. I fear there's enough potential for confusion in that matter
so I wouldn't necessarily change that name.

A bit of an aside, I've been thinking about synchronizing enumerable

objects.

Please be careful with the term "synchronize" - this is usually
interpreted in the context of concurrency (multiple threads).

For the sake of discussion lets say *=* means synchronize. So,

  ([1,2,3]*=*[7,8,9]).each {|a,b| puts "#{a},#{b}" }

  => 1,7
     2,8
     3,9

Then "indexing" can also be done with

  (enumobj*=*(0..enumobj.length-1)).each{|a,i|}

If a method #range is defined, this can be simplified too

  (enumobj*=*enumobj.range).each{|a,i|}

Is there a good way to do this?

[1,2,3].zip [7,8,9]

=> [[1, 7], [2, 8], [3, 9]]

    robert

···

On Monday 20 September 2004 08:54 am, Robert Klemme wrote:

"David A. Black" <dblack@wobblini.net> schrieb im Newsbeitrag
news:Pine.LNX.4.44.0409200600070.6220-100000@wobblini...

Hi --

> > > Or did you mean to use the hash key as index?
> >
> > Yes. I certainly didn't mean numerical indexes for hashes; that's

the

> > whole problem (well, part of the problem) with Hash#each_with_index

in

> > the first place. Also, by "defined as part of that class", I meant
> > defined according to the needs of that class, so that for arrays it
> > would be integers, for hashes the keys, etc.
>
> Ok, I see. I wouldn't change the behavior of #each_with_index since

that

> is likely to break a lot code. Read on for my suggestion.

I honestly doubt it would break much code. I have never seen
Hash#each_with_index used.

Possibly true.

> In my understanding Enumerable#each_with_index just goes through the
> enumerable and counts an index which can be used for printing or

counting

> or whatever. So I would not change this method. These indexes are

purely

> per enumeration and can change for any number of reasons.

I have the same understanding, and that's why I *would* change this
(frequently useless) method :slight_smile: See below....

:-))

> Additionally we should have Array#each_with_key and Hash#each_with_key

and

> AnyOtherLookupCollection#each_with_key (or call it #each_pair) that

yield

> key, value pairs. In the case of an Array the keys happen to be

identical

> with the indexes of a forward iteration but in case of a Hash keys are
> hash keys and thus different from indexes.
>
> I think the problem stems from the fact that we want to handle indexes

and

> keys with a single set of methods wile in fact these are different

things

> that only occasionally overlap.

Actually my suggestion earlier was to detach the concept of "index"
from Enumerable so that each enumerable class could define it as it
wanted to. That's why I'd like to push #each_with_index out of
Enumerable. It's the only "index" method in Enumerable, and I think
it can lead to too specific a concept of indexing for classes like
Hash where numerical indexes are essentially meaningless. (I guess
this might change if hashes become ordered....)

Well, you can use numbers as keys today already. :slight_smile:

I would prefer, in other words, for key and index to overlap in Hashes
as well as Arrays.

Ok, that's another resolution of the confusion. That would essentially
mean dropping of what I called "index" and leaving that to the user if
he/she ever needs it. That's ok with me, too, if it doesn't break too
much code. But in fact Hash#each_with_index seems a rather esoteric
application so that's probably the right way to go.

I just don't see enough advantage in having this
semi-magic #each_with_index at the level of Enumerable (semi-magic in
the sense that it does a kind of implicit to_a).

I don't view it as "implicit to_a" and thus no implicit magic. I view it
simply as counting elements. Btw, there is no array conversion involved
which can be proven like this:

class Foo
  include Enumerable
  def each; loop { yield 1 } end
end

=> nil

Foo.new.each_with_index {|a,i| p [i, a]; break if i > 10}

[0, 1]
[1, 1]
[2, 1]
[3, 1]
[4, 1]
[5, 1]
[6, 1]
[7, 1]
[8, 1]
[9, 1]
[10, 1]
[11, 1]

Or, if index always means a (to_a-based) numerical index, then
#each_index should be in Enumerable, and not left to the individual
classes. Then it would be clearer that index == 0-origin, possibly
meaningless (for unordered collections), numerical index. Classes
that specialized from this could either re-use the name index (for
example, a 1-origin collection), or introduce a set of methods with a
new name/concept (like key).

I prefer your first suggestion. So +1 for dropping
Enumerable#each_with_index in favor of Array#each_with_index (yield
element, numeric index) and Hash#each_with_index (yield value, key).

Now the only thing left is, we have to get Matz to agree. :slight_smile:

Kind regards

    robert

···

On Mon, 20 Sep 2004, Robert Klemme wrote:

Hi,

···

In message "Re: Array#index block and rdetect" on Mon, 20 Sep 2004 22:21:08 +0900, "David A. Black" <dblack@wobblini.net> writes:

Or, if index always means a (to_a-based) numerical index, then
#each_index should be in Enumerable, and not left to the individual
classes. Then it would be clearer that index == 0-origin, possibly
meaningless (for unordered collections), numerical index. Classes
that specialized from this could either re-use the name index (for
example, a 1-origin collection), or introduce a set of methods with a
new name/concept (like key).

This (numerical index) is what I thought when I designed
each_with_index. So I vote for introducing a new name.

              matz.

"trans. (T. Onoma)" <transami@runbox.com> schrieb im Newsbeitrag news:200409201143.55639.transami@runbox.com...

No. You *can* enumerate all elements (or all pairs) in a Hash.

Well, there is a a subtle distinction that can be drawn: by "enumerating a
hash", it undergoes a transformation and it isn't really a hash any more
--order has imposed upon it, and hashes have no order. Hence David's sense of
a "magic" to_a. Granted this is quite minor.

There is no transformation under the hood - neither technical nor conceptual: Hash#each just presents all key value pairs in some completely contingent order. No special order "has imposed upon it".

So, I agree with you. I just think the word 'index' is the wrong word, and
source of much the "confusion". If it's really needed the word 'enumerator'
would be better.

each_with_enumerator{|a,e| ... }

(Or perhaps just 'enum' for short)

IMHO not. An enumerator is somthing that does the enumeration or helps with it. #each_with_key is much better.

And then each_with_index can be defined as has been suggested, per class. For
Array it would just be an alias to the above I suppose.

Probably.

    robert

···

On Monday 20 September 2004 10:59 am, Robert Klemme wrote:

Huh. That's telling. Oh well, I was just trying to keep i local to the block
is all.

···

On Monday 20 September 2004 10:04 am, Robert Klemme wrote:

I'd say rather

i=-1
enumobj.each {|a| i+=1; ... }

Reason: scoping rules:
>> %w{aa bb cc}.each {|a| i=(i||-1)+1; p [a,i]}

["aa", 0]
["bb", 0]
["cc", 0]
=> ["aa", "bb", "cc"]

--
( o _ カラチ
// trans.
/ \ transami@runbox.com

I don't give a damn for a man that can only spell a word one way.
-Mark Twain

Wonderful! And I like the concept: a zipper :wink:

Thanks,
T.

···

On Monday 20 September 2004 10:04 am, Robert Klemme wrote:

>> [1,2,3].zip [7,8,9]
=> [[1, 7], [2, 8], [3, 9]]

--
( o _ カラチ
// trans.
/ \ transami@runbox.com

I don't give a damn for a man that can only spell a word one way.
-Mark Twain

Hi --

···

On Tue, 21 Sep 2004, Yukihiro Matsumoto wrote:

Hi,

In message "Re: Array#index block and rdetect" > on Mon, 20 Sep 2004 22:21:08 +0900, "David A. Black" <dblack@wobblini.net> writes:

>Or, if index always means a (to_a-based) numerical index, then
>#each_index should be in Enumerable, and not left to the individual
>classes. Then it would be clearer that index == 0-origin, possibly
>meaningless (for unordered collections), numerical index. Classes
>that specialized from this could either re-use the name index (for
>example, a 1-origin collection), or introduce a set of methods with a
>new name/concept (like key).

This (numerical index) is what I thought when I designed
each_with_index. So I vote for introducing a new name.

I liked Tom's idea of "counter". That seems to be more what it is.

David

--
David A. Black
dblack@wobblini.net