Issue #16891 has been updated by sam.saffron (Sam Saffron).


> Assuming we did not remove ruby2_keywords until a equally efficient replacement exists (which I'm assuming will be after 2.6 is EOL), what problems do you see?

Honestly ... no problem at all, the only issue I see is that we are in a rush to come up with an efficient replacement. 

If we come up with an efficient replacement for 3.0 then when finally we are ready to EOL 2.7 we can remove ruby2_keywords. So for example in Ruby 3.4 we could raise a loud deprecation on ruby2_keywords. If this waits till Ruby 3.1 ... then we are stuck carrying ruby2_keywords for another release.

To me the big thing we missed here is that certain apps only target latest Ruby so the preference there for application authors is to pick the efficient replacement for *args, over ruby2_keywords. They can move earlier than gem authors. 


As to the OP here.

My vote is 

1. Restore positional Hash Argument to Keyword Argument Conversion
2. Warning in verbose mode only for Ruby 3 
3. 1 release prior to removal of ruby2_keywords warn more loudly 

Don't touch any of the other edge cases for now. 

We are stuck with ruby2_keywords for a while sadly, so I don't see any reason to rush people to change code to use it. 

I also wonder is ruby2_keywords even necessary if we are still keeping restoration of positional hash around for a few more releases? 

Another bigger question is ... what if for: `def(*x); p x.class; end # x class is Arguments` 


Then lots of code needs no change. Especially if `Arguments` behaves mostly like the Array did in the past, we don't even need new syntax. Yes it is a big change ... but it keeps syntax of ruby cleaner.




----------------------------------------
Feature #16891: Restore Positional Argument to Keyword Conversion
https://bugs.ruby-lang.org/issues/16891#change-85713

* Author: jeremyevans0 (Jeremy Evans)
* Status: Open
* Priority: Normal
* Assignee: matz (Yukihiro Matsumoto)
----------------------------------------
Based on feedback from Rails-core, Matz has decided to postpone full separation of keyword and positional arguments (see https://discuss.rubyonrails.org/t/new-2-7-3-0-keyword-argument-pain-point/74980).  I think most Ruby-core developers were aware that fixing keyword argument separation issues can be fairly painful for libraries and applications that use keyword arguments extensively.

If we are going to discuss reversion or partial reversion of keyword argument separation, I think it would be best to address each aspect of keyword argument separation separately and decide how we want to handle each.  There are 4 aspects I am aware of.

## Positional Hash Argument to Keyword Argument Conversion

This is by far the most common issue when dealing with keyword argument separation.  I would estimate 95% of keyword argument separation issues/warnings are related to this change, and if we are to restore any behavior it should be this behavior.  Restoring positional hash argument to keyword argument conversion would allow the following code to continue to work:

```ruby
def foo(key: 42); end
foo({key: 42})

def bar(*a)
  foo(*a)
end
bar({key: 42})
```

Attached is a patch that restores the behavior (see below).

## Keyword Argument to Mandatory Positional Argument Conversion

This is probably the next most common issue with dealing with keyword argument separation.  I'm on the fence about whether we should try to restore this behavior. Restoring keyword argument to mandatory positional argument conversion would allow the following code to continue to work:

```ruby
def foo(h, **kw); end
foo(key: 42)
```

I don't think it would be difficult to restore this behavior, but I'm not sure it is worth doing so.

## Splitting of Keyword or Positional Hash Argument During Conversion

In Ruby 2.0-2.6, Ruby would split a hash with both symbol keys and non-symbol keys into two hashes, one symbol keyed hash used for keyword arguments, and one non-symbol keyed hash to be passed as a positional argument.

The need for this splitting appears to be rare. I have heard the splitting was not matz's intended behavior originally.  I know of only one user relying on this.  @mame's original keyword argument separation commit removed the splitting, but I added it back with deprecation warnings to ease the transition.  There's actually two types of splitting, one type when splitting keyword argument to positional argument, and another type when splitting positional argument to keyword argument.  Restoring the splitting would allow this code to continue to work:

```ruby
def foo(h={}, key: 42); [h, key] end
foo("key" => 43, key: 42)
foo({"key" => 43, key: 42})
```

Due to the very low usage of this behavior and questionable semantics, I recommend we do not restore this behavior.  Especially because the splitting no longer happens in 2.7 if arbitrary keywords are accepted by the method, since arbitrary keywords support non-symbol keys in 2.7. However, I don't think it is that difficult to restore this support if we decide to do so.

## Empty Keyword Argument Splat to Mandatory Positional Argument Conversion

In Ruby 2.7, empty keyword splats are removed and do not pass arguments.  However, if the method requires a positional argument, for compatibility Ruby 2.7 passes a new empty positional hash argument.  Restoring this behavior would allow the following code to continue to work:

```ruby
h = {}
def foo(a) a end
foo(**h)
```

I think very little code relies on this feature, and it would very painful and invasive to restore it, so I recommend we do not restore this behavior.

## Proposed behavior for Ruby 3.0

My preference would be to not change behavior at all. However, assuming we want to restore some backwards compatibility in regards to keyword argument separation, my proposal for Ruby 3.0 is to only restore positional argument to keyword argument conversion.  We convert positional hash argument to keyword arguments if:

* Method accepts keyword arguments
* Method is not passed keyword arguments
* Method is passed a hash as the final positional argument
* Method is passed more arguments than the minimum required

If the method does not accept arbitrary keywords, we only convert positional argument to keyword argument if the above are true and the final positional hash is empty or contains a symbol key.  It doesn't make sense to convert a positional hash to keywords if it has no symbol keys and the method does not accept arbitrary keywords.

When converting positional arguments to keyword arguments, we issue a warning in verbose mode in 3.0.  In 3.1 or 3.2, we can switch the warning to non-verbose mode, before removing it and enforcing full separation in the following version.

I propose to keep the current master branch behavior other than this change.

## Proposed behavior for Ruby 2.7.2

I propose we change the positional argument to keyword argument conversion warning to only issue in verbose mode and keep all other behavior the same.

## Patch

Attached is a patch that implements my proposal.  It does not include test or spec changes, as those will be extensive even for just the change I am proposing. I think we should agree on a proposal before working on changes to tests or specs.

---Files--------------------------------
keyword-hash-integration.diff (5.2 KB)


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