Bug #16473
closedNew deprecated warning disallows keyword arguments bypassing
Description
Hello. I see that ruby 2.7.0 prints unnecessary deprecated warning during arguments bypassing.
def kw(a: 1)
puts "kw #{a}"
end
def non_kw(a = {}, *args)
puts "non kw #{a}"
kw *args
end
non_kw({ :a => 2 }, :a => 2)
non_kw({ :a => 3 })
non_kw
The right output is:
non kw {:a=>2}
kw 2
non kw {:a=>3}
kw 1
non kw {}
kw 1
Ruby 2.7.0 provides deprecated warning:
warning: Using the last argument as keyword parameters is deprecated; maybe ** should be added to the call
*args
is bypassing arguments without any conversion. It looks like ruby converts last hash to keywords and than converts it back to hash. I think it is a bug.
Updated by puchuu (Andrew Aladjev) almost 5 years ago
- Subject changed from New deprecated warning disallows arguments bypassing to New deprecated warning disallows keyword arguments bypassing
Updated by jeremyevans0 (Jeremy Evans) almost 5 years ago
- Status changed from Open to Rejected
This behavior is expected. The positional hash argument is converted to keyword arguments when kw
is called. That is not going to work in Ruby 3 (see #14183), hence the warning.
For delegating argument to a method that accepts keywords, you should probably use ruby2_keywords
(if you also need to support older ruby versions):
ruby2_keywords :non_kw if respond_to?(:ruby2_keywords, true)
Updated by puchuu (Andrew Aladjev) almost 5 years ago
@jeremyevans0 (Jeremy Evans), what will be the right way to bypass keyword arguments?
def non_kw(a = {}, **keyword_args)
puts "non kw #{a}"
kw **keyword_args
end
This variant is wrong with ruby 2, because it provides:
non kw {:a=>2}
kw 2
warning: Using the last argument as keyword parameters is deprecated; maybe ** should be added to the call
warning: The called method `non_kw' is defined here
non kw {}
kw 3
non kw {}
kw 1
Will it work with ruby 3? Thank you.
Updated by jeremyevans0 (Jeremy Evans) almost 5 years ago
puchuu (Andrew Aladjev) wrote:
@jeremyevans0 (Jeremy Evans), what will be the right way to bypass keyword arguments?
As mentioned earlier, you should probably use ruby2_keywords
. In this particular case, even if you don't want to support earlier Ruby versions, because you don't want the positional hash argument being interpreted as keywords by non_kw
.
Updated by Dan0042 (Daniel DeLorme) almost 5 years ago
In this particular case there would be a bug if *args
had more than one element, so I think the cleaner fix would be
def non_kw(a = {}, b = {})
puts "non kw #{a}"
kw **b
end
I really think the ruby2_keywords
workaround should be strictly reserved for cases where portability and generic delegation require it.
Updated by Eregon (Benoit Daloze) almost 5 years ago
- Related to Feature #16463: Fixing *args-delegation in Ruby 2.7: ruby2_keywords semantics by default in 2.7.1 added
Updated by Eregon (Benoit Daloze) almost 5 years ago
This is one clear case where #16463 would solve it intuitively.