Very good question. The answer is "it depends". You're absolutely right to worry about modifying a collection while iterating over it if you move stuff around.

For example `ary.each{|i| ary << :bad_example}` is officially *undefined*.

On the other hand, `ary.each_with_index{|elem, i| ary[i] = elem * 2}` is safe (and a bad example, as we should use `map!` instead...) because the array structure is not changing, only the contents.

Here, we are not changing the structure of the hash (e.g. adding / removing keys), we are just changing the associated value, so it's safe.

If you think about it, there are many ways to implement `Hash#each` and each of them could react differently to keys being added/removed, so behavior is undefined. OTOH, there is really no reasonable implementation that would be thrown off by the above code, or by the first array example.

It's really too bad that Matz didn't think of covariance way back when; in particular, instead of having two aliases, `{}.collect` could have returned an array while `{}.map` could have been covariant and return a Hash...

Some examples in the wild:
https://github.com/rails/rails/blob/master/activerecord/lib/active_record/fixtures.rb#L569-571
https://github.com/rails/rails/blob/master/activemodel/lib/active_model/errors.rb#L255-257