Feature #15381

Let double splat call `to_hash` implicitly

Added by sawa (Tsuyoshi Sawada) 3 months ago. Updated 3 months ago.

Target version:


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:

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:


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_hash 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:

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.


Updated by sawa (Tsuyoshi Sawada) 3 months ago

Sorry, I meant to_h, not to_hash.

And in case my intention was not clear, in the example I gave for the double splat, I expected **nil to be evaluated as **{} due to nil.to_h # => {}.

Updated by shevegen (Robert A. Heiler) 3 months ago

I myself have used *foobar quite a lot in ruby code, such as in:

def foobar(*args)
  args.each # and do something then

and I have also used &: considerably often too. The most frequent
use case for me personally is to use &: together with .map(). This
is an area where I actually prefer e. g. .map(&:strip) as opposed
to something like .map {|line| line.strip } or something like
that. While I consider the second variant more readable to me,
the &: variant is significantly shorter. (& is not very pretty
though so I try to not use it too often).

I have not yet used **, I think (strangely enough; perhaps I have not
needed it so far). So I can not say much about the proposal itself
either way. I am both clueless and neither pro nor con. :)

I agree with the above reasoning of nil.to_h which makes sense (if
the functionality in itself is approved and I guess we have to ask
matz about this).

I think this is where matz has to decide whether ** should behave as
described, stay as it is (status quo), or have some other (implicit?)
meaning that was not yet mentioned. I really can not say either way,
but I think what is also said in the issue here is that * has a better
defined meaning right now than does **. So this is where I think matz
has to decide either way.

I would recommend adding this suggestion to an upcoming developer meeting,
but perhaps not for 2018 but 2019 instead - last dev meeting this year
should ideally be for the ruby x-mas release. :D

On a side note, does anyone have one or more good or simple use cases
for **? I am trying to find an example for where it may be used but
I do not have any local example.

Last but not least, although I understand that the example given was
mostly to illustrate a point, so that's fine; the * and ** variants
with () and conditionals, are a bit ugly. :P

I understand it is the illustration of an example but I really hope
people don't write code such as "**({a: 1} if some_condition)"; it
takes my brain quite some time to process.

Also available in: Atom PDF