Issue #16908 has been updated by jeremyevans0 (Jeremy Evans).
While your particular example is non-intuitive, there is a simple explanation for it. The first time `hash.shift` is called, `hash` is empty, so it returns the default value (`0`). It gets the default value by calling the default_proc for `hash` with a `nil` key. There is no better option since `hash.shift` isn't provided a key. The second time `hash.shift` is called, the hash is not empty, so it returns the first entry as a key value pair. I agree `Hash#shift` semantics with a default_proc are questionable, but I'm not sure if it could be improved.
I don't think we should change this behavior. It is expected that `Hash.new.shift` should return nil, as should `Hash.new(nil).shift` and `Hash.new{}.shift`.
`hash.shift` is used in conditionals:
```ruby
hash = {a: 1, b: 2}
while (k,v = hash.shift)
p [k, v]
end
```
If you change `Hash#shift` to return an array when the hash is empty, you've turned this into an infinite loop.
----------------------------------------
Bug #16908: Strange behaviour of Hash#shift when used with `default_proc`.
https://bugs.ruby-lang.org/issues/16908#change-85763
* Author: ioquatix (Samuel Williams)
* Status: Open
* Priority: Normal
* ruby -v: 2.7.0
* Backport: 2.5: UNKNOWN, 2.6: UNKNOWN, 2.7: UNKNOWN
----------------------------------------
I don't have any strong opinion about this, but I observed the following behaviour which I thought was confusing. Maybe it's okay, or maybe we should change it to be more consistent.
```
hash = Hash.new{|k,v| k[v] = 0}
hash.shift # => 0
hash.shift # => [nil, 0]
```
My feeling was, both cases should return `[nil, 0]`.
--
https://bugs.ruby-lang.org/
Unsubscribe: <mailto:ruby-core-request / ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>