Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why keyword arguments must be passed as hash with symbol keys, not string keys in Ruby?

We cannot pass keyword arguments as hash with string keys, keyword arguments works only with hash as symbol keys.

A simple example:

def my_method(first_name:, last_name: )
  puts "first_name: #{first_name} | last_name: #{last_name}"
end

my_method( {last_name: 'Sehrawat', first_name: 'Manoj'}) 
#=> first_name: Manoj | last_name: Sehrawat

my_method( {first_name: 'Bob', last_name: 'Marley'})
#=> first_name: Bob | last_name: Marley

my_method( {'first_name' => 'Kumar', 'last_name' => 'Manoj'})
#=> Error: missing keywords: first_name, last_name (ArgumentError)

What is the reasoning behind it?

like image 576
Manoj Sehrawat Avatar asked Feb 12 '15 12:02

Manoj Sehrawat


People also ask

How do you pass keyword arguments in Ruby?

So when you want to pass keyword arguments, you should always use foo(k: expr) or foo(**expr) . If you want to accept keyword arguments, in principle you should always use def foo(k: default) or def foo(k:) or def foo(**kwargs) .

What is hash and symbol in Ruby?

In Ruby, symbols are immutable names primarily used as hash keys or for referencing method names. Hashes and Symbols. Lesson 1 of 2. The Story So Far. Recall that hashes are collections of key-value pairs, where a unique key is associate…

What is HashWithIndifferentAccess in Rails?

HashWithIndifferentAccess is the Rails magic that paved the way for symbols in hashes. Unlike Hash , this class allows you to access data using either symbols ( :key ) or strings ( "key" ).


2 Answers

The short version would be because Matz says so - on this rubymine issue he comments

I am negative for the proposal. My opinion is that you should not (or no longer) use strings as keywords.

That actual issue is around something that happens as a consequence of this, but if Matz says no it's unlikely to happen. I don't know if he has further expounded on why he is against this.

like image 95
Frederick Cheung Avatar answered Oct 14 '22 06:10

Frederick Cheung


The implementation of * and ** could be relevant:

def gather_arguments(*arguments, **keywords)
  puts "arguments: #{arguments.inspect}"
  puts " keywords: #{keywords.inspect}"
end

gather_arguments('foo' => 1, bar: 2, 'baz' => 3, qux: 4)

Output:

arguments: [{"foo"=>1, "baz"=>3}]
 keywords: {:bar=>2, :qux=>4}
like image 27
Stefan Avatar answered Oct 14 '22 05:10

Stefan