Issue #11967 has been updated by Markus Doits.

Subject changed from Mixing kwargs with optional parameters change way method parameters are parsed to Mixing kwargs with optional parameters changes way method parameters are parsed

----------------------------------------
Bug #11967: Mixing kwargs with optional parameters changes way method parameters are parsed
https://bugs.ruby-lang.org/issues/11967#change-56009

* Author: Markus Doits
* Status: Open
* Priority: Normal
* Assignee: 
* ruby -v: ruby 2.3.0p0 (2015-12-25 revision 53290) [x86_64-darwin15]
* Backport: 2.0.0: UNKNOWN, 2.1: UNKNOWN, 2.2: UNKNOWN, 2.3: UNKNOWN
----------------------------------------
I have the following method:

    def test(first_param = nil, keyword_arg: nil)
      puts "first_param: #{first_param}"
      puts "keyword_arg: #{keyword_arg}"
    end

All the following calls do what I expect them to do:

    test(:something)
    #=> first_param: something
    #   keyword_arg:
    
    test(nil, keyword_arg: :keyword_arg)
    #=> first_param:
    #   keyword_arg: keyword_arg
    
    test({ first_param: :is_a_hash }, keyword_arg: :is_still_working)
    #=> first_param: {:first_param=>:is_a_hash}
    #   keyword_arg: is_still_working

But omitting the optional `keyword_arg` and passing a hash as first argument gives me an error:

    test(first_param: :is_a_hash)
    #=> test.rb:1:in `test': unknown keyword: first_param (ArgumentError)
    #           from test.rb:12:in `<main>'

I'd expect it to set `first_param` to `{ first_param: :is_hash }` and `keyword_arg` being `nil`.

It seems it is interpreting every hash as keyword arg:

    test(keyword_arg: :should_be_first_param)
    #=> first_param:
    #   keyword_arg: should_be_first_param

This should have set `first_param` to `{ keyword_arg: :should_be_first_param }`, leaving `keyword_arg` `nil` in my opinion.

Making the first parameter *mandatory* and everything works like I'd expect to:

    def test(first_param, keyword_arg: nil)
      puts "first_param: #{first_param}"
      puts "keyword_arg: #{keyword_arg}"
    end

    test(first_param: :is_a_hash)
    #=> first_param: {:first_param=>:is_a_hash}
    #   keyword_arg:

    test(keyword_arg: :should_be_first_param)
    #=> first_param: {:keyword_arg=>:should_be_first_param}
    #=> keyword_arg:

I'd expect making a parameter optional does not change the way parameters are parsed.

Is this a parser oddity or expected behaviour?



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