Issue #12022 has been updated by Tsuyoshi Sawada.
This is a duplicate, or is at least related to #11860.
----------------------------------------
Bug #12022: Inconsistent behavior with splatted named arguments
https://bugs.ruby-lang.org/issues/12022#change-56977
* Author: Colin Fulton
* Status: Open
* Priority: Normal
* Assignee:
* ruby -v: 2.2.2 and 2.3.0
* Backport: 2.0.0: UNKNOWN, 2.1: UNKNOWN, 2.2: UNKNOWN, 2.3: UNKNOWN
----------------------------------------
# The Bug
When an empty hash is splatted (using \*\*) into a call of a method with no parameters, the empty hash is passed in as a positional argument *instead* of doing nothing. This causes an ArgumentError, which is confusing because when you splat an empty array into a method that doesn't accept any arguments the method is called without raising an error.
Similarly, if you splat a hash into a method that only has positional arguments, the method is called with the hash added as the last argument. This either causes an ArgumentError or unexpected bugs.
## Examples
(tested in MRI 2.2.2 and 2.3.0)
```ruby
def without_parameters
# some code
end
def with_parameters(*args)
args
end
def with_one_parameter(arg)
arg
end
empty_hash = {}
filled_hash = { example: "value" }
array = []
without_parameters(*array)
# calls the method without an error because `array' is empty
without_parameters(**empty_hash)
# unexpectedly raises an ArgumentError despite `empty_hash' being empty
with_parameters(**empty_hash)
# unexpectedly returns [{}] instead of []
with_parameters(**filled_hash)
# unexpectedly returns [{ example: "value }] instead of raising an ArgumentError
with_one_parameter(**empty_hash)
with_one_parameter(**filled_hash)
# both unexpectedly do not raise an ArgumentError
```
# Further Information
This behavior makes it more difficult to do things like write specialized decorator classes using #method_missing. The following example does not work if the method being called does not have any named parameters. The variable named_args gets passed in as a positional argument, causing ArgumentErrors or unexpected bugs:
```ruby
class TrivialDecoratorExample
def initialize(value)
@value = value
end
def method_missing(name, *args, **named_args, &block)
@value.send(name, *args, **named_args, &block)
end
end
```
Instead one has to write something really ugly like:
```ruby
def method_missing(name, *args, **named_args, &block)
if @value.method(name)
.parameters
.any? { |type, _| [:keyreq, :key].include?(type) }
@value.send(name, *args, **named_args, &block)
elsif named_args.empty?
@value.send(name, *args, &block)
else
raise ArgumentError.new
end
end
```
--
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>