title: What does the double-splat do in a method call?
body: <p>While preparing for the <a href="https://www.ruby.or.jp/en/certification/examination/" rel="nofollow noreferrer">Ruby Association Certified Ruby Programmer Exam</a>, I was solving the <a href="https://github.com/ruby-association/prep-test/blob/master/gold.md" rel="nofollow noreferrer">prep test</a> and came upon this scenario:</p>
  
  <pre><code>def add(x:, y:, **params)
    z = x + y
  
    params[:round] ? z.round : z
  end
  
  
  p add(x: 3, y: 4) #=&gt; 7 // no surprise here
  p add(x: 3.75, y: 3, round: true) #=&gt; 7 // makes total sense
  options = {:round =&gt; true}; p add(x: 3.75, y: 3, **options) #=&gt; 7 // huh?
  </code></pre>
  
  <p>Now, I know how the double-splat can be used in converting params in an argument to a hash, e.g.:</p>
  
  <pre><code>def splat_me(a, *b, **c)
    puts "a = #{a.inspect}"
    puts "b = #{b.inspect}"
    puts "c = #{c.inspect}"
  end
  
  splat_me(1, 2, 3, 4, a: 'hello', b: 'world')
  
  #=&gt; a = 1
  #=&gt; b = [2, 3, 4]
  #=&gt; c = {:a=&gt;"hello", :b=&gt;"world"}
  </code></pre>
  
  <p>However, I also know that you can't double-splat randomly.</p>
  
  <pre><code>options = {:round =&gt; true}
  **options
  
  #=&gt; SyntaxError: (irb):44: syntax error, unexpected **arg
  #=&gt; **options
  #=&gt;   ^
  </code></pre>
  
  <hr>
  
  <p><strong>Question</strong>:</p>
  
  <p>What is the use of the double-splat (<code>**</code>) in method <em>calls</em> (not definitions)?</p>
  
  <p>Plainly put, when is this:</p>
  
  <pre><code>options = {:round =&gt; true}; p add(x: 3.75, y: 3, **options)
  </code></pre>
  
  <p>Better than this:</p>
  
  <pre><code>options = {:round =&gt; true}; p add(x: 3.75, y: 3, options)
  </code></pre>
  
  <hr>
  
  <p>Edit: <strong>Testing the usefulness of the double-splat (none found)</strong></p>
  
  <p>Args are the same with or without it.</p>
  
  <pre><code>def splat_it(**params)
    params
  end
  
  opts = {
    one: 1,
    two: 2,
    three: 3
  }
  
  a = splat_it(opts)   #=&gt; {:one=&gt;1, :two=&gt;2, :three=&gt;3}
  b = splat_it(**opts) #=&gt; {:one=&gt;1, :two=&gt;2, :three=&gt;3}
  
  a.eql? b # =&gt; true
  </code></pre>
  
  <p>I mean, you can even pass a hash to a method defined with keyword params without a problem, and it'll intelligently assign the appropriate keywords:</p>
  
  <pre><code>def splat_it(one:, two:, three:)
    puts "one   = #{one}"
    puts "two   = #{two}"
    puts "three = #{three}"
  end
  
  opts = {
    one: 1,
    two: 2,
    three: 3
  }
  
  a = splat_it(opts)   #=&gt; {:one=&gt;1, :two=&gt;2, :three=&gt;3}
  #=&gt; one   = 1
  #=&gt; two   = 2
  #=&gt; three = 3
  
  b = splat_it(**opts) #=&gt; {:one=&gt;1, :two=&gt;2, :three=&gt;3}
  #=&gt; one   = 1
  #=&gt; two   = 2
  #=&gt; three = 3
  </code></pre>
  
  <p>Double splat on a random class with the appropriate <code>to_h</code> and <code>to_hash</code> methods doesn't do anything that can't be done without it:</p>
  
  <pre><code>Person = Struct.new(:name, :age)
  
  Person.class_eval do
    def to_h
      {name: name, age: age}
    end
  
    alias_method :to_hash, :to_h
  end
  
  bob = Person.new('Bob', 15)
  
  p bob.to_h #=&gt; {:name=&gt;"Bob", :age=&gt;15}
  
  
  def splat_it(**params)
    params
  end
  
  splat_it(**bob) # =&gt; {:name=&gt;"Bob", :age=&gt;15}
  splat_it(bob)   # =&gt; {:name=&gt;"Bob", :age=&gt;15}
  </code></pre>