From: sawadatsuyoshi@... Date: 2016-02-14T03:55:53+00:00 Subject: [ruby-core:73796] [Ruby trunk Bug#12022] Inconsistent behavior with splatted named arguments 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: