I noticed what I find to be a very surprising behavior with the **
(double-splat) operator in Ruby 2.1.1.
When key-value pairs are used before a **hash
, the hash remains unmodified; however, when key-value pairs are only used after the **hash
, the hash is permanently modified.
h = { b: 2 }
{ a: 1, **h } # => { a: 1, b: 2 }
h # => { b: 2 }
{ a: 1, **h, c: 3 } # => { a: 1, b: 2, c: 3 }
h # => { b: 2 }
{ **h, c: 3 } # => { b: 2, c: 3 }
h # => { b: 2, c: 3 }
For comparison, consider the behavior of the single-*
operator on arrays:
a = [2]
[1, *a] # => [1, 2]
a # => [2]
[1, *a, 3] # => [1, 2, 3]
a # => [2]
[*a, 3] # => [2, 3]
a # => [2]
The array remains unchanged throughout.
Do we suppose the sometimes-destructive behavior of **
is intentional, or does it look more like a bug?
In either case, where is the documentation describing how the **
operator is meant to work?
I also asked this question in the Ruby Forum.
UPDATE
The bug is fixed in Ruby 2.1.3+.
The answers to the question seem to be:
It's probably a bug, rather than intentional.
The behavior of the
**
operator is documented very briefly in the core library rdoc.
Thanks to the suggestions of several commenters, I've posted the bug to the Ruby trunk issue tracker.
UPDATE:
The bug was fixed in changeset r45724. The comment there was "keyword splat should be non-destructive," which makes this an authoritative answer.
I noticed the diff between 2.1.5 and 2.3.1
Example is an irb method and a way of calling it
$ irb
>> def foo(opts) opts end
=> :foo
>> foo a: 'a', ** {a: 'b'}
In 2.1.5 the following results in retaining value
=> {:a=>"a"}
In 2.3.1 the value is 'b'
(irb):2: warning: duplicated key at line 2 ignored: :a
=> {:a=>"b"}
I am not sure which it should be?
In 2.3.1 the hash provided as double splat overrides the same key of the first item in a list.
来源:https://stackoverflow.com/questions/23282342/double-splat-operator-destructively-modifies-hash-is-this-a-ruby-bug