Where is it legal to use ruby splat operator?
Asked Answered
V

2

19

Splats are cool. They're not just for exploding arrays, although that is fun. They can also cast to Array and flatten arrays (See http://github.com/mischa/splat/tree/master for an exhaustive list of what they do.)

It looks like one cannot perform additional operations on the splat, but in 1.8.6/1.9 the following code throws "unexpected tSTAR":

foo = bar || *zap #=> unexpected tSTAR

Whereas this works:

foo = *zap || bar #=> works, but of limited value

Where can the splat appear in an expression?

Volsci answered 22/4, 2009 at 9:58 Comment(0)
T
15

First, precedence isn't an issue here, because foo = bar || (*zap) works no better. The general rule of thumb is that you cannot perform additional operations on a splat. Even something as simple as foo = (*zap) is invalid. This applies to 1.9 as well.

Having said that, what do you expect foo = bar || *zap to do, if it worked, that is different than foo = bar || zap? Even in a case like a, b = bar || *zap (which also doesn't work), a, b = bar || zap accomplishes what I'd assume would be the same thing.

The only situation where this might make any sense is something like a, b = foo, bar || *zap. You should find that most cases where you would want to use this are covered by a, b = foo, *(bar || zap). If that doesn't cover your case, you should probably ask yourself what you really hope to accomplish by writing such an ugly construct.


EDIT:

In response to your comments, *zap || bar is equivalent to *(zap || bar). This demonstrates how low the splat's precedence is. Exactly how low is it? The best answer I can give you is "pretty low".

For an interesting example, though, consider a method foo which takes three arguments:

def foo(a, b, c)
  #important stuff happens here!
end

foo(*bar = [1, 2, 3]) will splat after the assignment and set the arguments to 1, 2, and 3 respectively. Compare that with foo((*bar = [1, 2, 3])) which will complain about having the wrong number of arguments (1 for 3).

Tayib answered 22/4, 2009 at 14:46 Comment(4)
The example is for illustration only. I accomplished everything I want in life many years ago, and now I simply enjoy discovering the depths of Ruby. Don't you? :)Volsci
Also, is it possible to be more precise? What additional operation is being performed on the splat in bar || *zap versus *zap || bar?Volsci
Sorry, I meant to mention that: *zap || bar is equivalent to *(zap || bar). This implies how late the splat binds. Exactly how late is it? The best answer I can give you is "pretty late". For an interesting example, consider a method foo which takes three arguments: foo(*c = [1, 2, 3]) will splat after the assignment and set the arguments to 1, 2, and 3 respectively.Tayib
Thanks very much Pesto - please can you the stuff about late binding and your example to the top of your answer, then I'll accept it?Volsci
S
9

The "splat operator" is in fact not an operator at all but a token defined in the Ruby grammar. A read through grammar.y or the Ruby grammar in BNF form* will tell you that it is allowed as the last or only argument:

  • in a method definition (except for an optional last &foo)
  • in a method call (except for an optional last &foo)
  • on the LHS of as assignment, for example: a, b, *cs = [1,2,3,4]
  • on the RHS of an assignment, for example: a, b, c = 1, 2, *[3,4,5]
  • in the when clause of a case statement
Santoro answered 8/4, 2011 at 18:4 Comment(2)
Is this for Ruby 1.8, or Ruby 1.9?Jeroldjeroma
@ReinHenrichs Where can you find Ruby grammar?Godsend

© 2022 - 2024 — McMap. All rights reserved.