Issue #16853 has been updated by mame (Yusuke Endoh).


@sylvain.joyeux

Hi!  I read [your comment in the discuss RubyOnRails](https://discuss.rubyonrails.org/t/new-2-7-3-0-keyword-argument-pain-point/74980/13).  I'm sorry for bothering you about this change.  Let me explain a bit.


This change was introduced into 2.7 because the old behavior was unintentional.  In fact, Ruby 2.0.0-p0 was the same as the current (2.7) behavior.

```
$ ./bin/ruby-2.0.0-p0 -ve '
def provides(h = {}, **kw)
  p kw
end

provides("some" => "strings", as: "name")
'
ruby 2.0.0p0 (2013-02-24 revision 39474) [x86_64-linux]
{"some"=>"strings", :as=>"name"}
```

But the behavior was changed to reject non-symbol keys, and it was done without matz's confirmation.  So in a sense, this is a bug fix.

That being said, we don't change such a long-working behavior without a reason.  The reason why it was changed is because there are some methods that want to accept both symbol and non-symbol keys: `where(id: 42)` and `where("table.id" => 42)`.  This will not work in 3.0 if keyword arguments are completely separated from positional ones.  So, non-symbol keys were allowed to keyword arguments.


BTW, in that forum, you said "adding a keyword splat will break code".  This is true, even without this 2.7 change.  Please consider:

```
def m(mapping = {}); mapping; end

m(k: 1) #=> {:k=>1}
```

and if you add `**kw`,

```
def m(mapping = {}, **kw); mapping; end

m(k: 1) #=> {} # changed
```

Fixing this issue was (one of) the original motivation of 3.0 keyword arguments (#14183): consistently passing `k: 1` to keywords, and `{ k: 1 }` to positional.  This is very simple and completely solves the ambiguity.  But unfortunately, it turned out too breaking.  We decided to continue allowing the automatic conversion from keywords to positional.  I want to solve the ambiguity in future, but it is very tough.


To know your pain point precisely, I'd like to ask you a question: can you manually separate non-symbol keys?

```
def provides(h = {}, **kw)
  kw.each {|k, v| h[k] = v if k.is_a?(Symbol) }

  ...main code...
end
```

I think this code works perfectly even in 2.6.  I'm sorry for asking you to change your code, but if we change anything, anyone must pay a cost.  (No change require no cost, but I believe that it means the death of the language.)  To minimize the sum of costs, I'd like to know how pain your pain point is.

Again, I'm really sorry for bothering you, and thank you for taking time for this issue.

----------------------------------------
Bug #16853: calling bla(hash, **kw) with a string-based hash passes the strings into **kw (worked < 2.7)
https://bugs.ruby-lang.org/issues/16853#change-85656

* Author: sylvain.joyeux (Sylvain Joyeux)
* Status: Rejected
* Priority: Normal
* ruby -v: 2.7.1p83
* Backport: 2.5: UNKNOWN, 2.6: UNKNOWN, 2.7: UNKNOWN
----------------------------------------
The following code

~~~
def bla(hash = {}, **kw)
    puts "H: #{hash}"
    puts "K: #{kw}"
end

bla "some" => "string"
~~~

**silently** outputs the following (no warnings about deprecation of keyword parameters-from-hash)

~~~
H: {}
K: {"some"=>"string"}
~~~

While 2.6.5 (and versions before it) gave

~~~
H: {"some"=>"string"}
K: {}
~~~

I would expect "the warning" that started appearing in 2.7, and **definitely** not having strings in a keyword argument hash.



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