One example in The Ruby Way claims that in the following snippet second
line shuffles the a (i.e., makes an array consisting of the same
elements as a, but in a different order).
One example in The Ruby Way claims that in the following snippet second
line shuffles the a (i.e., makes an array consisting of the same
elements as a, but in a different order).
It appears that #each is being affected by the slicing of the array that it is acting on. By the time it gets to the third element, it's the last one. So it stops.
It doesn't seem to do that in 1.6.x; I assume #each worked on a copy of the array back then...
To fix it in later versions, use a.dup.collect instead. That should fix the odd behavior.
HTH,
Mark
···
On Jul 17, 2004, at 3:12 PM, Alexey Verkhovsky wrote:
One example in The Ruby Way claims that in the following snippet second
line shuffles the a (i.e., makes an array consisting of the same
elements as a, but in a different order).
One example in The Ruby Way claims that in the following snippet second
line shuffles the a (i.e., makes an array consisting of the same
elements as a, but in a different order).
By the way, if you just want to shuffle an Array you can also use the much simpler ary.sort_by { rand }. (It will get minimally biased with containers containing millions of elements, but that can be fixed by using Array.new(32) { rand } instead of rand.)
So, Ruby iterators operate on the original collection and let you modify
the collection in the process. Another fact useful to remember.
This is, by the way, one thing I like about Java iterators: they are
fail-safe in such scenarios. E.g.
List list = new ArrayList(2);
list.add(new Object());
list.add(new Object());
Iterator i = list.iterator();
i.next(); // this is OK
list.add(new Object()); // list gets changed
i.next(); // throws ConcurrentModificationException
IMHO, an exception here is The Right Thing (TM). At least, it saved me
Best regards,
Alex
···
On Sun, 2004-07-18 at 01:43, Mark Sparshatt wrote:
It's because the block passed to collect is changing the contents of a,
so it doesn't reach all the elements of a.
One example in The Ruby Way claims that in the following snippet second
line shuffles the a (i.e., makes an array consisting of the same
elements as a, but in a different order).
By the way, if you just want to shuffle an Array you can also use the much simpler ary.sort_by { rand }. (It will get minimally biased with containers containing millions of elements, but that can be fixed by using Array.new(32) { rand } instead of rand.)
And by the way, the code which modified the array while iterating
was probably ill-advised from the beginning, although it did work
in 1.6.8.
I'm not sure that an exception would be The Right Thing, but I do wonder why it no longer works on a copy of the array? Allowing modification of the actual array as you iterate over it seems dangerous.
But there must have been a reason for abandoning the original behavior... Perhaps it was a performance issue?
cheers,
Mark
···
On Jul 17, 2004, at 4:12 PM, Alexey Verkhovsky wrote:
On Sun, 2004-07-18 at 01:43, Mark Sparshatt wrote:
It's because the block passed to collect is changing the contents of a,
so it doesn't reach all the elements of a.
So, Ruby iterators operate on the original collection and let you modify
the collection in the process. Another fact useful to remember.
This is, by the way, one thing I like about Java iterators: they are
fail-safe in such scenarios. E.g.
List list = new ArrayList(2);
list.add(new Object());
Iterator i = list.iterator();
i.next(); // this is OK
list.add(new Object()); // list gets changed
i.next(); // throws ConcurrentModificationException
IMHO, an exception here is The Right Thing (TM). At least, it saved me
from my own stupid mistakes more than once.
A smilie was inadvertently omitted in my earlier post. It should have
said "The Right Thing (TM) :)"
Life is full of compromises, and on the issue of what to do with stale
iterators, there are at least three choices:
1. Nothing (fast and dangerous)
2. Iterate over a copy (safe and slow)
3. Iterate over the original, but detect stale iterators (the middle
way, much safer than 1 and somewhat faster than 2).
Each of the three choices has pros and cons.
All I'm saying is that in my personal experience Java's
ConcurrentModificationException has prevented or exposed many bugs that
otherwise would be subtle and probably very costly affairs. Which is why
I like it.
But then, the most important difference between Ruby and Java is that
the former lets you do anything, and that includes shooting yourself in
the foot, too. The latter, meantime, does not believe that you REALLY
know what you are doing.
Best regards,
Alex
···
On Sun, 2004-07-18 at 03:04, Mark Hubbart wrote:
I'm not sure that an exception would be The Right Thing
I'm not sure that an exception would be The Right Thing
A smilie was inadvertently omitted in my earlier post. It should have
said "The Right Thing (TM) :)"
Life is full of compromises, and on the issue of what to do with stale
iterators, there are at least three choices:
1. Nothing (fast and dangerous)
2. Iterate over a copy (safe and slow)
3. Iterate over the original, but detect stale iterators (the middle
way, much safer than 1 and somewhat faster than 2).
Each of the three choices has pros and cons.
All I'm saying is that in my personal experience Java's
ConcurrentModificationException has prevented or exposed many bugs that
otherwise would be subtle and probably very costly affairs. Which is why
I like it.
But then, the most important difference between Ruby and Java is that
the former lets you do anything, and that includes shooting yourself in
the foot, too. The latter, meantime, does not believe that you REALLY
know what you are doing.
Best regards,
Alex
One alternative solution is to provide for all three options using a resettable flag. Kinda like $SAFE for security.