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


Dan0042 (Daniel DeLorme) wrote:
> In that case I'd like to make one last suggestion.
> =

> For a method with `*args`, if the method is called with keyword arguments=
, flag `args` in some way (instance variable?) so that, in that method only=
, a call with `*args` would result in the last argument being passed as a k=
eyword argument. Yes, it's a hack, but it's a better hack than `pass_keywor=
ds` imho.

You can't make this an instance-specific flag and easily contain the scope =
to that method only.  The user could pass `args` (not `*args`) as a argumen=
t to another method and splat `args` in that method.

Also, using an instance-specific flag doesn't handle this type of delegatio=
n:

```ruby
def foo(*args)
  bar(*args.map{|arg| something(arg)})
end
```

> This would make the migration less tedious, less confusing, less error-pr=
one, and postpone this whole delegation mess to a date when it's easier to =
deal with. I really think this migration should be split into "should be do=
ne now" and "easier to do once 2.6 is no longer supported". My 2=A2

The approach you are proposing handles the simplest case fine and opens ano=
ther Pandora's box of issues for other cases.  And if you want to split the=
 migration into "should be done now" vs. "easier to do once 2.6 is no longe=
r supported", that's exactly what `pass_keywords` allows.  You can use `pas=
s_keywords` now, and once 2.6 is no longer supported, you can switch all de=
legation to `(*args, **kw)`.

----------------------------------------
Misc #16157: What is the correct and *portable* way to do generic delegatio=
n?
https://bugs.ruby-lang.org/issues/16157#change-81548

* Author: Dan0042 (Daniel DeLorme)
* Status: Open
* Priority: Normal
* Assignee: =

----------------------------------------
With the keyword argument changes in 2.7 we must now specify keyword argume=
nts explicitly when doing generic delegation. But this change is not compat=
ible with 2.6, where it adds an empty hash to the argument list of methods =
that do not need/accept keyword arguments.

To illustrate the problem:

```ruby
class ProxyWithoutKW < BasicObject
  def initialize(target)
    @target =3D target
  end
  def method_missing(*a, &b)
    @target.send(*a, &b)
  end
end

class ProxyWithKW < BasicObject
  def initialize(target)
    @target =3D target
  end
  def method_missing(*a, **o, &b)
    @target.send(*a, **o, &b)
  end
end

class Test
  def args(*a)   a  end
  def arg(a)     a  end
  def opts(**o)  o  end
end
                                          # 2.6        2.7              3.0
ProxyWithoutKW.new(Test.new).args(42)     # [42]       [42]             [42=
]        ok
ProxyWithoutKW.new(Test.new).arg(42)      # 42         42               42 =
         ok
ProxyWithoutKW.new(Test.new).opts(k: 42)  # {:k=3D>42}   {:k=3D>42} +warn  =
 [{:k=3D>42}]  incompatible with >=3D 2.7
ProxyWithKW.new(Test.new).args(42)        # [42, {}]   [42]             [42=
]        incompatible with <=3D 2.6
ProxyWithKW.new(Test.new).arg(42)         # error      42               42 =
         incompatible with <=3D 2.6
ProxyWithKW.new(Test.new).opts(k: 42)     # {:k=3D>42}   {:k=3D>42} +warn  =
 {:k=3D>42}    must ignore warning? cannot use pass_positional_hash in 2.6
```

I don't know how to solve this, so I'm asking for the **official** correct =
way to write portable delegation code. And by **portable** I mean code that=
 can be used in gems that target ruby 2.6 and above.




-- =

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>