Issue #12022 has been updated by Colin Fulton.

ruby -v set to 2.2.2 and 2.3.0

----------------------------------------
Bug #12022: Inconsistent behavior with splatted named arguments
https://bugs.ruby-lang.org/issues/12022#change-56703

* 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>