From: eregontp@... Date: 2021-07-04T10:00:13+00:00 Subject: [ruby-core:104495] [Ruby master Bug#18011] `Method#parameters` is incorrect for forwarded arguments Issue #18011 has been updated by Eregon (Benoit Daloze). jeremyevans0 (Jeremy Evans) wrote in #note-4: > I think methods that use `ruby2_keywords`, either explicitly or implicitly through argument forwarding, should handle `parameters` consistently. For me `...` and explicit `ruby2_keywords` should/can be two different things. `...` need not be implemented by `ruby2_keywords`, and IMHO CRuby should not expose that implementation detail (which may change BTW, and is not necessarily accurate on other Ruby implementations). > However, I'm fine with all `ruby2_keywords` methods adding `[:keyrest, :**]` as opposed to adding `[:ruby2_keywords]`. The `:keyrest` approach may be more backwards compatible. It is not fully ideal to pretend there is a keyrest paramater when there is not in the method definition, but I think this is a good compromise. At least from the `:**` name we can find out it's added synthetically and is not from the source definition (`method(def m(*,**); end).parameters => [[:rest], [:keyrest]]`). And technically `ruby2_keywords` accepts or forwards keyword arguments, so it makes sense. > Note that from a caller's perspective, `[[:rest, :*]]` and `[[:rest, :*], [:keyrest, :**]]` have identical behavior. Both accept an arbitrary number of positional argument and arbitrary keywords. From `[[:rest, :*]]` one might expect any keyword args given by the caller are made positional in the callee, and that's not really the case with `ruby2_keywords` which keeps the information they were given as kwargs. I think @jeremyevans0's solution of adding `[:keyrest, :**]` is the best here. It also nicely matches an implementation which would convert `(...)` into `(*, **, &)` (the natural/intuitive form for that). ---------------------------------------- Bug #18011: `Method#parameters` is incorrect for forwarded arguments https://bugs.ruby-lang.org/issues/18011#change-92763 * Author: josh.cheek (Josh Cheek) * Status: Open * Priority: Normal * ruby -v: ruby 3.0.1p64 (2021-04-05 revision 0fb782ee38) [arm64-darwin20] * Backport: 2.6: UNKNOWN, 2.7: UNKNOWN, 3.0: UNKNOWN ---------------------------------------- When asking a method about its parameters, forwarded arguments say they are a rest and a block (`wrapper1` in the example below). However, when we use that signature, it raises an ArgumentError (`wrapper2` in the example below). When I add a keyrest to the signature, it works as expected (`wrapper3` in the example below). So I think forwarded arguments should include a keyrest in the output of `Method#parameters` ```ruby def wrapped(ord, kw:) = [ord, {kw: kw}] methods = [ def wrapper1(...) = wrapped(...), def wrapper2(*r, &b) = wrapped(*r, &b), def wrapper3(*r, **k, &b) = wrapped(*r, **k, &b), ] methods.each do |name| puts File.read(__FILE__)[/#{name}\(.*?\)/] puts " params: #{method(name).parameters.inspect}" puts " result: #{(method(name).call 123, kw: 456 rescue $!).inspect}" puts end ``` Output: ``` wrapper1(...) params: [[:rest, :*], [:block, :&]] result: [123, {:kw=>456}] wrapper2(*r, &b) params: [[:rest, :r], [:block, :b]] result: # wrapper3(*r, **k, &b) params: [[:rest, :r], [:keyrest, :k], [:block, :b]] result: [123, {:kw=>456}] ``` -- https://bugs.ruby-lang.org/ Unsubscribe: