https://bugs.ruby-lang.org/https://bugs.ruby-lang.org/favicon.ico?17113305112016-01-31T05:43:44ZRuby Issue Tracking SystemRuby master - Bug #11993: foo(hash) is handled like foo(**hash)https://bugs.ruby-lang.org/issues/11993?journal_id=568122016-01-31T05:43:44Zavit (Andrew Vit)andrew@avit.ca
<ul></ul><p>See <a class="issue tracker-1 status-6 priority-4 priority-default closed" title="Bug: Mixing kwargs with optional parameters changes way method parameters are parsed (Rejected)" href="https://bugs.ruby-lang.org/issues/11967">#11967</a> for Marc-Andre's explanation.</p> Ruby master - Bug #11993: foo(hash) is handled like foo(**hash)https://bugs.ruby-lang.org/issues/11993?journal_id=739112018-09-05T16:45:36Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<ul><li><strong>Status</strong> changed from <i>Open</i> to <i>Rejected</i></li></ul><p>First, <code>foo(b: 1)</code> has been exactly the same as <code>foo({b: 1})</code> since Ruby 1.8 at least. It is parsed exactly the same way. It's syntax sugar.</p>
<pre><code>require 'ripper'
Ripper.sexp('foo(a : 1)') == Ripper.sexp('foo({a : 1})') # => true
</code></pre>
<p>As you note, the <code>**</code> operator is not needed in many cases, but there are cases where it matters. You can see a difference in these three cases:</p>
<p>a) It merges keyword arguments:</p>
<pre><code>h = {a: 1, b: 2}
p(h, c: 3) # => {:a=>1, :b=>2}, then {:c=>3}
p(**h, c: 3) # {:a=>1, :b=>2, :c=>3}
</code></pre>
<p>b) It insures that a hash is viewed as keyword arguments:</p>
<pre><code>h = {'a' => 1}
p(h) # {"a"=>1}
p(**h) # => TypeError (hash key "a" is not a Symbol)
</code></pre>
<p>c) It differentiates between an actual empty hash <code>{}</code> and nothing at all</p>
<pre><code>def foo(x)
p x
end
e = {}
foo('hello', **e) # => 'hello'
foo('hello', e) # => ArgumentError (wrong number of arguments (given 2, expected 1))
</code></pre>
<p>Note that some corner cases may not perfectly handled yet (<a class="issue tracker-1 status-5 priority-4 priority-default closed" title="Bug: Hash splat of empty hash should not create a positional argument. (Closed)" href="https://bugs.ruby-lang.org/issues/15078">#15078</a>)</p>
<p>In summary: using <code>**</code> improves legibility by making the intention crystal clear, makes your code stricter and allows you to easily merge options. There is also discussion to make the use of <code>**</code> required in some cases in Ruby 3.0 (see <a class="issue tracker-2 status-5 priority-4 priority-default closed" title="Feature: "Real" keyword argument (Closed)" href="https://bugs.ruby-lang.org/issues/14183">#14183</a>).</p>
<p>I'm closing this, but will reopen if need be.</p>