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>