[ruby-core:119589] [Ruby master Feature#15381] Let double splat call `to_h` implicitly

Issue #15381 has been updated by zverok (Victor Shepelev).
`{}.merge(**obj)` => obj is explicitly splatted but conversion is done via #to_hash instead of #to_h. It makes no sense, as many many people have commented through the years.
I don’t think it can be treated as “explicitly” (invoking hash conversion); it is rather “we apply an operator, which would work with kind-of hash”. We can apply the same argument to `1 + obj`: “you see, I am _explicitly_ summing it with an integer; why is it not converted with `to_int`?”
`**obj` is my intent, not a typo.
What if it _is_ a typo/error? Assume this API (frequent in many long-living codebases, which are partially old-style “options hash” and partially new-style “keyword arguments”): ```ruby def process(something, options = {}) # ... other_method(**options) end ``` Now, if the user misuses it (by mistake or misunderstanding) and passes some, say, ActiveRecord model as a second parameter, then, with `to_h`, it would be successfully unpacked, and might go this way (as “keyword arguments” which shouldn’t have been) through several more delegating methods before failing in completely different place—with an extremely hard to debug problem. So, what we are weighting here are: * convenience of unpacking non-hashes into keyword arguments (BTW, what exactly is the use case for this convenience?..), vs. * problem of things being _unintentionally_ unpacked, considering how many objects have `to_h` method; basically failing to “fail early” (where the mistake was made) and instead passing the mistake for who-know-which depth. I honestly fail to see the use case for `to_h` being used with `**` that outweighs the possible problems (other than `**(params if condition?)`, which was actually handled). ---------------------------------------- Feature #15381: Let double splat call `to_h` implicitly https://bugs.ruby-lang.org/issues/15381#change-110210 * Author: sawa (Tsuyoshi Sawada) * Status: Open ---------------------------------------- The single splat calls `to_a` implicitly on the object (if it is not an array already) so that, for example, we have the convenience of writing conditions in an array literal: ```ruby a = [ *(:foo if some_condition), *(:bar if another_condition), ] ``` And the ampersand implicitly calls `to_proc` on the object (if it is not a proc already) so that we can substitute a block with an ampersand followed by a symbol: ```ruby some_method(&:some_method_name) ``` Unlike the single splat and ampersand, the double splat does not seem to implicitly call a corresponding method. I propose that the double splat should call `to_h` implicitly on the object if it not already a Hash so that we can, for example, write a condition in a hash literal as follows: ```ruby h = { **({a: 1} if some_condition), **({b: 2) if another_condition), } ``` There may be some other benefits of this feature that I have not noticed yet. -- https://bugs.ruby-lang.org/
participants (1)
-
zverok (Victor Shepelev)