From: Sven Suska Date: 2007-09-10T19:33:40+09:00 Subject: Splat for Hashes -- was: Named argument passing, and method_args extension Hello, On Do, 2007-September-06 10:17:11, Brian Candler wrote: > Quick question - what are the current thoughts about named argument passing > in future versions of Ruby? > > [...] > Taking this one step further, has it been considered that splat might be > applied to a hash in the same way? e.g. > > def func(a, b, c) > [a, b, c] > end > > func( *{:c=>3, :b=>2, :a=>1} ) # => [1,2,3] :-) Wow, I really like this idea a lot. I think this could be taken even a bit further, by allowing the splat outside method headers: h = {:c=>3, :b=>2, :a=>1} a, b, c = *h p [a, b, c] # => [1,2,3] The most important reason why I like this, is because it would give us not only named arguments, but named return values too, leading to a nice symmetry: def get_data ... {:name => name, :zip => zip} # the old way would be: [name, zip] end # and then we would simply write: name, zip = get_data # or just as well: zip, name = get_data # same effect, more robust Yes, hashes are already used to return multiple values today, but I think the clumsy notation ( d = get_data name = d[:name] zip = d[:zip] ) prevents many programmers from adopting this practice. To sum up: Yes. I would really like to see something like this in Ruby 3.0 > P.S. By symmetry, I'd suggest that any 'unused' elements could be available > as a hash too: > > def func(a, b, c=3, *d) > p a, b, c, d > end > > func( *{:a=>1, :b=>2, :e=>5, :f=>6} ) > # 1 > # 2 > # 3 > # {:e=>5, :f=>6} > > However this does mean that the receiver of *d would have to be able to > cope with receiving either an Array or a Hash. OK, I would call that the problem of "reverse splatting". I.e.: If we allow splat for both arrays and hashes, we will be able to determine the type of the splat from the object if the operator is on the right-hand side. But we won't have any information, if it is on the left-hand side: *x = a, b, c This could be interpreted as both x = [a, b, c] or x = {:a=>a, :b=>b, :c=>c} A simple way to deal with that, would be to declare the old interpretation (array) as the only one for a LHS-splat. And the semantics of Brian's example could be preserved in this approach, because it not only has a LHS-splat, but also a RHS-splat with it. Essentially it boils down to: *d = *{:e=>5, :f=>6} And we just have to assume an internal "splat reduction", giving: d = {:e=>5, :f=>6} However, it might be nice to have a way to force reverse hash splatting, for example by a new prefix operator ** **h = a, b, c # => h = {:a=>a, :b=>b, :c=>c} ... but also inviting cans of trouble, like **h = a, b, 42 # result?? # perhaps # => h = {:a=>a, b=>b, 2=>42} (position used as key) Yes, at this point I really wish that there be a unified Hash-Array data structure, as they have in Oz or Lua. Bye for now Regards Sven