Issue #14183 has been updated by jeremyevans0 (Jeremy Evans).


koic (Koichi ITO) wrote:
> Thank you very much. It is solved by `**h`.
> However, in the following complicated case, it seems difficult to solve u=
sing `**h`. This is an interesting use case :-)
> =

> ```ruby
> def do_something(*args, &block)
>   yield 'yield_self', {expected: 'then'}
> end
> =

> do_something do |code, expected:, use: expected, instead_of: code|
>   puts "code: =A0 =A0 =A0 #{code}"
>   puts "expected: =A0 #{expected}"
>   puts "use: =A0 =A0 =A0 =A0#{use}"
>   puts "instead_of: #{instead_of}"
> end
> ```

Unless I'm missing something, it should be sufficient to drop the braces in=
 the yield, so you are calling the block with keywords instead of a hash:

```ruby
def do_something(*args, &block)
  yield 'yield_self', expected: 'then'
end
```

This will still work correctly if the block accepts a hash argument instead=
 of keywords.

----------------------------------------
Feature #14183: "Real" keyword argument
https://bugs.ruby-lang.org/issues/14183#change-83095

* Author: mame (Yusuke Endoh)
* Status: Closed
* Priority: Normal
* Assignee: =

* Target version: Next Major
----------------------------------------
In RubyWorld Conference 2017 and RubyConf 2017, Matz officially said that R=
uby 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 desi=
gn is chosen because of compatibility, but it is fairly complex, and has be=
en a source of many corner cases where the behavior is not intuitive.  (Som=
e related tickets: #8040, #8316, #9898, #10856, #11236, #11967, #12104, #12=
717, #12821, #13336, #13647, #14130)

In Ruby 3, a keyword argument will be completely separated from normal argu=
ments.  (Like a block parameter that is also completely separated from norm=
al 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 `**` synt=
ax:

```
# 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 k=
eyword 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 ke=
yword argument
def foo(a, b, c, key: 1)
end
h =3D {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 =3D {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 interp=
reted as keyword argument, or vice versa.
* Ruby 3.0 will use the new semantics.

---Files--------------------------------
vm_args.diff (4.19 KB)
vm_args_v2.diff (4.18 KB)


-- =

https://bugs.ruby-lang.org/

Unsubscribe: <mailto:ruby-core-request / ruby-lang.org?subject=3Dunsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>