Array#index block and rdetect

M

Markus

class BlockIteratorProxy

%w(
count
begin
end
proxy
).each{|a| attr a, true}

def intialize proxy
@proxy = nil
end

def method_missing(*a,&b);proxy.send(*a,&b);end
end

OK, I'm stumped. Why write it that way instead of:

attr_accessor :count,:begin,:end,:proxy

which, AFAIK, does exactly the same thing. And why pass in proxy
(without parens?) and not use it? Or are we in some idiom space that
I'm totally unfamiliar with?


-- MarkusQ
 
R

Robert Klemme

trans. (T. Onoma) said:
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
 
T

trans. (T. Onoma)

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".

Sounds like a contradiction in terms to me: "some completely contingent
order" != "special order"? It's still order either way. Nonetheless, even
though a Hash by definition has no order, I doubt anything in a computer
system lacks for order ;)
IMHO not. An enumerator is somthing that does the enumeration or helps
with it. #each_with_key is much better.

Sorry, guess I wasn't clear enough. I didn't mean the per class methods;
rather the common Enumerable#each_with_index method, i.e. giving it a new
name. But David seems to like #each_with_counter anyway, which is fine with
me.

T.
 
R

Robert Klemme

trans. (T. Onoma) said:
Sounds like a contradiction in terms to me: "some completely contingent
order" != "special order"? It's still order either way. Nonetheless, even
though a Hash by definition has no order, I doubt anything in a computer
system lacks for order ;)

Exactly. That's why the term "order" does not make any sense unless a data
structure has a recognizable order. A hash does not have that - an array
has it. And there is no transformation - neither for Hash#each,
Hash#each_with_index or the Array counterparts.
Sorry, guess I wasn't clear enough. I didn't mean the per class methods;
rather the common Enumerable#each_with_index method, i.e. giving it a new
name. But David seems to like #each_with_counter anyway, which is fine
with
me.

+1

robert
 
R

Robert Klemme

trans. (T. Onoma) said:
Sounds like a contradiction in terms to me: "some completely contingent
order" != "special order"? It's still order either way. Nonetheless, even
though a Hash by definition has no order, I doubt anything in a computer
system lacks for order ;)

Exactly. That's why the term "order" does not make any sense unless a data
structure has a recognizable order. A hash does not have that - an array
has it. And there is no transformation - neither for Hash#each,
Hash#each_with_index or the Array counterparts.
Sorry, guess I wasn't clear enough. I didn't mean the per class methods;
rather the common Enumerable#each_with_index method, i.e. giving it a new
name. But David seems to like #each_with_counter anyway, which is fine
with
me.

+1

robert
 
Y

Yukihiro Matsumoto

Hi,

In message "Re: Array#index block and rdetect"

|> 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.

Sorry for being noisy.

Do you mean we should rename each_with_index to each_with_counter? In
that case, do you have any estimation about compatibility?

matz.
 
G

Gavin Sinclair

|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.

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
 
D

David A. Black

Hi --

Hi,

In message "Re: Array#index block and rdetect"

|> 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.

Sorry for being noisy.

Feel free :)
Do you mean we should rename each_with_index to each_with_counter? In
that case, do you have any estimation about compatibility?

Here's one possibility. I don't think this would be bad for
compatibility, because Array would have its *_index methods, and I
don't think #each_with_index is used much (ever?) for anything except
arrays and maybe array subclasses.

Enumerable:

each_with_counter # "dumb" counters, for every enumerable,
each_counter # strictly based on incrementing through
# #each

Array:

each_with_index # either very similar to, or identical to,
each_index # the *_counter methods (because that
# happens to be how arrays work).

Hash and other enumerable classes:

In addition to the *_counter methods, each enumerable class
can have its own, "smart" methods (just as Array does with
its *_index methods). They can have "index" in the name,
if appropriate -- but they do not have to. (There are no
Enumerable#*_index methods.)


In other words: keep the dumbest, most general behavior in Enumerable,
and let the various enumerable classes keep/override/add to, etc.,
that behavior.


David
 
T

trans. (T. Onoma)

Here's one possibility. I don't think this would be bad for
compatibility, because Array would have its *_index methods, and I
don't think #each_with_index is used much (ever?) for anything except
arrays and maybe array subclasses.

Enumerable:

each_with_counter # "dumb" counters, for every enumerable,
each_counter # strictly based on incrementing through
# #each

Array:

each_with_index # either very similar to, or identical to,
each_index # the *_counter methods (because that
# happens to be how arrays work).

Hash and other enumerable classes:

In addition to the *_counter methods, each enumerable class
can have its own, "smart" methods (just as Array does with
its *_index methods). They can have "index" in the name,
if appropriate -- but they do not have to. (There are no
Enumerable#*_index methods.)

If I may add to this. In addition to the above, Hash would have:

each_with_index {|value,key| ...

And then all other Enumerable classes, would have 'each_with_index' defined
specifically for them to do the same as they do now, but with a warning,
"#each_with_index will change to #each_with_counter. Change now to ensure
future compatibility." Or something like that.

No big deal so far b/c very few programs use each_with_index for anything but
Array.

The larger compatibility issue would come from Hash#each being changed to
return only value and not key. This is a bigger change, but has advantages
b/c then hash and array can be better used interchangeably, e.g.

a = [1,2,3]
h = {:a=>1,:b=>2,:c=>3}

def show_succ(x)
x.each {|v| puts v.succ}
end

show_succ(a)
show_succ(h)

Would work, but now it doesn't:

NoMethodError: undefined method `succ' for [:b, 2]:Array

T.

--
( o _ カラãƒ
// trans.
/ \ (e-mail address removed)

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

Yukihiro Matsumoto

Hi,

In message "Re: Array#index block and rdetect"

|Here's one possibility. I don't think this would be bad for
|compatibility, because Array would have its *_index methods, and I
|don't think #each_with_index is used much (ever?) for anything except
|arrays and maybe array subclasses.
|
| Enumerable:
|
| each_with_counter # "dumb" counters, for every enumerable,
| each_counter # strictly based on incrementing through
| # #each

No need for each_counter, for there's no way for general enumerables
to map from counters to values. If it's possible, it's rather
suitable to be called as index. By the way, do you agree with the
word 'counter'? It's kinda burden for me, non English speaker, to
tell the word nuance.

| Array:
|
| each_with_index # either very similar to, or identical to,
| each_index # the *_counter methods (because that
| # happens to be how arrays work).

No objection here.

| Hash and other enumerable classes:
|
| In addition to the *_counter methods, each enumerable class
| can have its own, "smart" methods (just as Array does with
| its *_index methods). They can have "index" in the name,
| if appropriate -- but they do not have to. (There are no
| Enumerable#*_index methods.)

Do you have any opinion toward Hash#each_with_index?

matz.
 
R

Randy W. Sims

David said:
Enumerable:

each_with_counter # "dumb" counters, for every enumerable,
each_counter # strictly based on incrementing through
# #each

I'm not sure I understand the justification for these. It's simple
enough to provide your own counter if needed:

counter = 0
var.each { |item| counter += 1; puts counter }

A little less candy, but same effect. I'm not sure I see the benefit.

Randy.
 
R

Robert Klemme

Yukihiro Matsumoto said:
Hi,

In message "Re: Array#index block and rdetect"
|Here's one possibility. I don't think this would be bad for
|compatibility, because Array would have its *_index methods, and I
|don't think #each_with_index is used much (ever?) for anything except
|arrays and maybe array subclasses.
|
| Enumerable:
|
| each_with_counter # "dumb" counters, for every enumerable,
| each_counter # strictly based on incrementing through
| # #each

No need for each_counter, for there's no way for general enumerables
to map from counters to values. If it's possible, it's rather
suitable to be called as index. By the way, do you agree with the
word 'counter'? It's kinda burden for me, non English speaker, to
tell the word nuance.

I'd prefer to keep #each_with_index because that has least impact on
existing code.
| Array:
|
| each_with_index # either very similar to, or identical to,
| each_index # the *_counter methods (because that
| # happens to be how arrays work).

No objection here.

| Hash and other enumerable classes:
|
| In addition to the *_counter methods, each enumerable class
| can have its own, "smart" methods (just as Array does with
| its *_index methods). They can have "index" in the name,
| if appropriate -- but they do not have to. (There are no
| Enumerable#*_index methods.)

Do you have any opinion toward Hash#each_with_index?

Here's my suggestion:

class Array
alias :each_with_key :each_with_index
def keys; (0...size); end
def values; self; end
def to_assoc; inject([]) {|a,e| a<<[a.size, e]} end
end

class Hash
def each_with_key
each {|k,v| yield v,k}
end

alias :to_assoc :to_a
end

Note that I deliberately maintained each_with_index as well as the order
of key and value (first value, then key).

Note also, that #to_a is a problem when we want to make Hash and Array
more interchangable: Hash#to_a returns keys and values while Array#to_a
just returns values. That's why I put in #to_assoc. Also #sort doesn't
fit the pattern... Maybe we should rather go with a thin wrapper around
Array (or a sub class) that implements these methods in a Hash compatible
way.

Still I feel we didn't capture all aspects of this...

Kind regards

robert
 
M

Martin DeMello

trans. (T. Onoma) said:
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.

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
 
M

Martin DeMello

Randy W. Sims said:
counter = 0
var.each { |item| counter += 1; puts counter }

A little less candy, but same effect. I'm not sure I see the benefit.

In general, the easier ('cheaper') it is to do something, the more uses
tend to be found for it. Compare the use of regexps in languages that
let them be inlined with that in languages where you have to say re =
Regexp.compile(string) every time you want one.

martin
 
D

David A. Black

Hi --

I'm not sure I understand the justification for these. It's simple
enough to provide your own counter if needed:

counter = 0
var.each { |item| counter += 1; puts counter }

A little less candy, but same effect. I'm not sure I see the benefit.

each_with_counter is just a rename of each_with_index, which already
exists.


David
 
D

David A. Black

Hi --

Yukihiro Matsumoto said:
Hi,

In message "Re: Array#index block and rdetect"


I'd prefer to keep #each_with_index because that has least impact on
existing code.

I'm really not worried about that, since Array would still have it
(see below). Also, all of this is in the spirit of assuming there
will be backward-incompatible changes in 2.0.
| Array:
|
| each_with_index # either very similar to, or identical to,
| each_index # the *_counter methods (because that
| # happens to be how arrays work).

No objection here.

| Hash and other enumerable classes:
|
| In addition to the *_counter methods, each enumerable class
| can have its own, "smart" methods (just as Array does with
| its *_index methods). They can have "index" in the name,
| if appropriate -- but they do not have to. (There are no
| Enumerable#*_index methods.)

Do you have any opinion toward Hash#each_with_index?

Here's my suggestion:

class Array
alias :each_with_key :each_with_index
def keys; (0...size); end
def values; self; end
def to_assoc; inject([]) {|a,e| a<<[a.size, e]} end
end

class Hash
def each_with_key
each {|k,v| yield v,k}
end

alias :to_assoc :to_a
end

Note that I deliberately maintained each_with_index as well as the order
of key and value (first value, then key).

It comes down in part to terminology. I don't like calling array
indexes "keys", even though I completely understand how they relate to
hash keys. It just seems artificial; no one does it.

I also don't like the word "index" for the "dumb counter" in
Enumerable. A lot of the reason we're discussing changes is that the
word "index" is used in different ways, giving the impression that
there is a connection between arguably unconnected things.
Note also, that #to_a is a problem when we want to make Hash and Array
more interchangable: Hash#to_a returns keys and values while Array#to_a
just returns values. That's why I put in #to_assoc. Also #sort doesn't
fit the pattern... Maybe we should rather go with a thin wrapper around
Array (or a sub class) that implements these methods in a Hash compatible
way.

I'm still not happy with the idea of wrappers and such. I think it
should be possible to have arrays and hashes just be what they are.
They have some points of overlap, but they really don't have to be
constrained to be too similar to each other.


David
 
D

David A. Black

Hi --

Hi,

In message "Re: Array#index block and rdetect"

|Here's one possibility. I don't think this would be bad for
|compatibility, because Array would have its *_index methods, and I
|don't think #each_with_index is used much (ever?) for anything except
|arrays and maybe array subclasses.
|
| Enumerable:
|
| each_with_counter # "dumb" counters, for every enumerable,
| each_counter # strictly based on incrementing through
| # #each

No need for each_counter, for there's no way for general enumerables
to map from counters to values. If it's possible, it's rather
suitable to be called as index. By the way, do you agree with the
word 'counter'? It's kinda burden for me, non English speaker, to
tell the word nuance.

I think it's OK. "counter" is very similar to an expression like:
"maintaining a counter in a loop". It also has a "dumb" sound (in a
good way :) that keeps it separate from index and key. (Index and
key both suggest a direct lookup, whereas counter suggests an external
numbering which could apply to a non-lookup enumerable as well as a
lookup enumerable.)
| Array:
|
| each_with_index # either very similar to, or identical to,
| each_index # the *_counter methods (because that
| # happens to be how arrays work).

No objection here.

| Hash and other enumerable classes:
|
| In addition to the *_counter methods, each enumerable class
| can have its own, "smart" methods (just as Array does with
| its *_index methods). They can have "index" in the name,
| if appropriate -- but they do not have to. (There are no
| Enumerable#*_index methods.)

Do you have any opinion toward Hash#each_with_index?

I prefer "key" for hashes and "index" for arrays (I know Robert
disagrees), so I would tend to avoid "index" names for hash methods.
But I have no deep theoretical argument here. I'm just following what
I think is common usage (index/element for array, key/value for hash).


David
 
T

trans. (T. Onoma)

I prefer "key" for hashes and "index" for arrays (I know Robert
disagrees), so I would tend to avoid "index" names for hash methods.
But I have no deep theoretical argument here.  I'm just following what
I think is common usage (index/element for array, key/value for hash).

For sake of interchangeability (after all that's the upside of ducktyping)
have an alias for both:

Array
def each_with_index
alias each_with_key each_with_index

Hash
def each_with_key
alias each_with_index each_with_key

Good?


T.
 
R

Robert Klemme

David A. Black said:
Hi --

Yukihiro Matsumoto said:
Hi,

In message "Re: Array#index block and rdetect"


I'd prefer to keep #each_with_index because that has least impact on
existing code.

I'm really not worried about that, since Array would still have it
(see below). Also, all of this is in the spirit of assuming there
will be backward-incompatible changes in 2.0.
| Array:
|
| each_with_index # either very similar to, or identical to,
| each_index # the *_counter methods (because that
| # happens to be how arrays work).

No objection here.

| Hash and other enumerable classes:
|
| In addition to the *_counter methods, each enumerable class
| can have its own, "smart" methods (just as Array does with
| its *_index methods). They can have "index" in the name,
| if appropriate -- but they do not have to. (There are no
| Enumerable#*_index methods.)

Do you have any opinion toward Hash#each_with_index?

Here's my suggestion:

class Array
alias :each_with_key :each_with_index
def keys; (0...size); end
def values; self; end
def to_assoc; inject([]) {|a,e| a<<[a.size, e]} end
end

class Hash
def each_with_key
each {|k,v| yield v,k}
end

alias :to_assoc :to_a
end

Note that I deliberately maintained each_with_index as well as the order
of key and value (first value, then key).

It comes down in part to terminology.

I suspect the whole thread is about terminology. :)
I don't like calling array
indexes "keys", even though I completely understand how they relate to
hash keys. It just seems artificial; no one does it.

I'm open to suggestions of better names. My point is just that Array and
Hash can both be viewed as associative storages with different legal keys
(and performance implications). I had already the case where I wanted to
exchange both but had to do some adjustmens to code. But I will readily
agree that this does not happen very often. Partly it's an aesthetical
thing... :)
I also don't like the word "index" for the "dumb counter" in
Enumerable. A lot of the reason we're discussing changes is that the
word "index" is used in different ways, giving the impression that
there is a connection between arguably unconnected things.

Yeah, true. In that light counter might be the better choice.
I'm still not happy with the idea of wrappers and such. I think it
should be possible to have arrays and hashes just be what they are.
They have some points of overlap, but they really don't have to be
constrained to be too similar to each other.

I don't like the wrapper also, it just occurred to me that there is no
easy way to make Array and Hash similar *and* keep compatibility. The
longer we discuss this issue, the more I find the target of
interchangeability questionable. Even if we would not change anything,
I'd regard this insight a positive effect of this discussion. Thanks for
bearing with me and taking your time, David!

Kind regards

robert
 
Y

Yukihiro Matsumoto

Hi,

In message "Re: Array#index block and rdetect"

|For sake of interchangeability (after all that's the upside of ducktyping)
|have an alias for both:

Arrays have number index, and hashes have arbitrary type of keys, so
that there should hardly be the case of need for interchangeability
between them. Do you have any example of the usage?

Currently, I'd rather feel that it's good to avoid the term "index"
for hashes, for example, renaming IndexError to KeyError for Hash
class.


matz.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,773
Messages
2,569,594
Members
45,125
Latest member
VinayKumar Nevatia_
Top