Project

General

Profile

Feature #14183

"Real" keyword argument

Added by mame (Yusuke Endoh) over 2 years ago. Updated 5 months ago.

Status:
Closed
Priority:
Normal
Assignee:
-
Target version:
[ruby-core:84255]

Description

In RubyWorld Conference 2017 and RubyConf 2017, Matz officially said that Ruby 3.0 will have "real" keyword arguments. AFAIK there is no ticket about it, so I'm creating this (based on my understanding).

In Ruby 2, the keyword argument is a normal argument that is a Hash object (whose keys are all symbols) and is passed as the last argument. This design is chosen because of compatibility, but it is fairly complex, and has been a source of many corner cases where the behavior is not intuitive. (Some related tickets: #8040, #8316, #9898, #10856, #11236, #11967, #12104, #12717, #12821, #13336, #13647, #14130)

In Ruby 3, a keyword argument will be completely separated from normal arguments. (Like a block parameter that is also completely separated from normal arguments.)
This change will break compatibility; if you want to pass or accept keyword argument, you always need to use bare sym: val or double-splat ** syntax:

# The following calls pass keyword arguments
foo(..., key: val)
foo(..., **hsh)
foo(..., key: val, **hsh)

# The following calls pass **normal** arguments
foo(..., {key: val})
foo(..., hsh)
foo(..., {key: val, **hsh})

# The following method definitions accept keyword argument
def foo(..., key: val)
end
def foo(..., **hsh)
end

# The following method definitions accept **normal** argument
def foo(..., hsh)
end

In other words, the following programs WILL NOT work:

# This will cause an ArgumentError because the method foo does not accept keyword argument
def foo(a, b, c, hsh)
  p hsh[:key]
end
foo(1, 2, 3, key: 42)

# The following will work; you need to use keyword rest operator explicitly
def foo(a, b, c, **hsh)
  p hsh[:key]
end
foo(1, 2, 3, key: 42)

# This will cause an ArgumentError because the method call does not pass keyword argument
def foo(a, b, c, key: 1)
end
h = {key: 42}
foo(1, 2, 3, h)

# The following will work; you need to use keyword rest operator explicitly
def foo(a, b, c, key: 1)
end
h = {key: 42}
foo(1, 2, 3, **h)

I think here is a transition path:

  • Ruby 2.6 (or 2.7?) will output a warning when a normal argument is interpreted as keyword argument, or vice versa.
  • Ruby 3.0 will use the new semantics.

Files

vm_args.diff (4.19 KB) vm_args.diff jeremyevans0 (Jeremy Evans), 03/25/2019 10:48 PM
vm_args_v2.diff (4.18 KB) vm_args_v2.diff mame (Yusuke Endoh), 03/29/2019 10:29 AM

Related issues

Related to Backport200 - Backport #8040: Unexpect behavior when using keyword argumentsClosednagachika (Tomoyuki Chikanaga)03/08/2013Actions
Related to Ruby master - Bug #8316: Can't pass hash to first positional argument; hash interpreted as keyword argumentsClosedmame (Yusuke Endoh)Actions
Related to Ruby master - Bug #9898: Keyword argument odditiesClosed06/03/2014Actions
Related to Ruby master - Bug #10856: Splat with empty keyword args gives unexpected resultsClosednobu (Nobuyoshi Nakada)Actions
Related to Ruby master - Bug #11236: inconsistent behavior using ** vs hash as method parameterClosedActions
Related to Ruby master - Bug #11967: Mixing kwargs with optional parameters changes way method parameters are parsedRejectedmatz (Yukihiro Matsumoto)Actions
Related to Ruby master - Bug #12717: Optional argument treated as kwargClosedmatz (Yukihiro Matsumoto)Actions
Related to Ruby master - Bug #12821: Object converted to Hash unexpectedly under certain method callClosedActions
Related to Ruby master - Bug #13336: Default Parameters don't workClosedActions
Related to Ruby master - Bug #13647: Some weird behaviour with keyword argumentsClosedmatz (Yukihiro Matsumoto)Actions
Related to Ruby master - Bug #14130: Keyword arguments are ripped from the middle of hash if argument have default valueClosednobu (Nobuyoshi Nakada)Actions
Related to Ruby master - Bug #15078: Hash splat of empty hash should not create a positional argument.Closedmatz (Yukihiro Matsumoto)Actions
Related to Ruby master - Bug #14415: Empty keyword hashes get assigned to ordinal args.ClosedActions
Related to Ruby master - Bug #12022: Inconsistent behavior with splatted named argumentsClosedActions
Related to Ruby master - Bug #11860: Double splat does not work on empty hash assigned via variableClosedActions
Related to Ruby master - Bug #10708: In a function call, double splat of an empty hash still calls the function with an argumentClosedmatz (Yukihiro Matsumoto)Actions
Related to Ruby master - Bug #11068: unable to ommit an optional keyarg if the previous arg is an optional hashClosedActions
Related to Ruby master - Bug #11039: method_missing の *args 引数に symbol をキーにした hash だけを渡すと エラーとなるClosedActions
Related to Ruby master - Bug #10994: Inconsistent behavior when mixing optional argument and keyword splatClosedActions
Related to Ruby master - Bug #10293: splatting an empty hash in a method invocation sends an argument to the method (should send nothing)Closednobu (Nobuyoshi Nakada)Actions
Related to Ruby master - Bug #15753: unknown keyword when passing an hash to a method that accepts a default argument and a named argumentClosedActions
Related to Ruby master - Misc #16188: What are the performance implications of the new keyword arguments in 2.7 and 3.0?Openjeremyevans0 (Jeremy Evans)Actions
Related to Ruby master - Misc #16157: What is the correct and *portable* way to do generic delegation?OpenActions

Also available in: Atom PDF