Sunday, May 1, 2011

Where is it legal to use ruby splat operator?

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?

From stackoverflow
  • 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).

    Dave Nolan : 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? :)
    Dave Nolan : Also, is it possible to be more precise? What additional operation is being performed on the splat in bar || *zap versus *zap || bar?
    Pesto : 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.
    Dave Nolan : 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?
  • Look at this post, it might clarify a little bit more about the splat operator => http://bit.ly/raflabs_foo_splat

    Alex Baranosky : great article raf

0 comments:

Post a Comment