From: "Eregon (Benoit Daloze)" Date: 2022-03-14T17:41:52+00:00 Subject: [ruby-core:107903] [Ruby master Bug#18633] proc { |a, **kw| a } autosplats and treats empty kwargs specially Issue #18633 has been updated by Eregon (Benoit Daloze). This is the logic in TruffleRuby, basically we can see the inconsistency and the need for a hack just to support this case: ```java private boolean shouldConsiderDestructuringArrayArg(Arity arity) { if (arity.getRequired() == 1 && arity.getOptional() == 0 && !arity.hasRest() && arity.hasKeywordsRest()) { // Special case for: proc { |a, **kw| a }.call([1, 2]) => 1 // Seems inconsistent: https://bugs.ruby-lang.org/issues/18633 return true; } if (!arity.hasRest() && arity.getRequired() + arity.getOptional() <= 1) { // If we accept at most 0 or 1 arguments, there's never any need to destructure return false; } else if (arity.hasRest() && arity.getRequired() == 0) { // If there are only a rest argument and optional arguments, there is no need to destructure. // Because the first optional argument (or the rest if no optional) will take the whole array. return false; } else { return true; } } ``` Whether a Proc should autosplat besides special case is otherwise not too complicated. The only runtime checks (in addition to these static checks) are: * a single argument is passed, and it responds to `#to_ary`. * if kwargs are passed, no autosplatting ---------------------------------------- Bug #18633: proc { |a, **kw| a } autosplats and treats empty kwargs specially https://bugs.ruby-lang.org/issues/18633#change-96841 * Author: Eregon (Benoit Daloze) * Status: Open * Priority: Normal * Backport: 2.6: UNKNOWN, 2.7: UNKNOWN, 3.0: UNKNOWN, 3.1: UNKNOWN ---------------------------------------- ```ruby irb(main):005:0> proc { |a| a }.call([1, 2]) => [1, 2] irb(main):006:0> proc { |a, **kw| a }.call([1, 2]) => 1 # should be [1, 2] irb(main):007:0> proc { |a, kw: 42| a }.call([1, 2]) => 1 # should be [1, 2] ``` What's the reason for `proc { |a, **kw| a }` to autosplat? It seems inconsistent with the resolution of #16166, and it seems nobody would want that behavior (it loses arguments but the user extremely likely did not want that). Could we change it so procs never autosplat, just like `proc { |a| a }`. My understanding of the change in #16166 is to reflect the fact positional and kwargs are separated, and so adding `**kw` or `kw:` should never change anything if only positional arguments are passed. This breaks in this case though. Also I noticed: ```ruby irb(main):010:0> proc { |a, **kw| a }.call([1, 2]) => 1 irb(main):011:0> proc { |a, **kw| a }.call([1, 2], **{}) => [1, 2] ``` Which is really unfortunate as it shows a difference between passing `**{}` or nothing. AFAIK passing `**{}` or nothing should always be equivalent, but it breaks in this case. (from https://bugs.ruby-lang.org/issues/16166#note-14) -- https://bugs.ruby-lang.org/ Unsubscribe: