I want to test the return value of a parallel assignment, and I write puts (x, y = 1, 2)
, but it doesn't work, and print the error message:
SyntaxError: (irb):74: syntax error, unexpected ',', expecting ')'
puts (x,y =1,2)
^
(irb):74: syntax error, unexpected ')', expecting end-of-input
Is there anything wrong?
You have two problems.
The space between puts
and the (
prevents the parenthesized list from being interpreted as an argument list. Once you put a space after a method name, any argument list has to be outside of parentheses, and any parenthesized parts must be a legal expressions. In Ruby, (x,y,z)
is not a legal single expression, so you get the above error.
If you remove the space, you get this:
> puts(x, y = 1, 2)
NameError: undefined local variable or method `x' for main:Object
That's because of your second problem:
The statement puts(x,y = 1,2)
is parsed as puts(x, y=1, 2)
; that is, Ruby interprets it as passing three arguments to puts
: x
is the first, y=1
is the second, and 2
is the third. Since the x
is not on the left side of an assignment and hasn't been defined yet, you get the above error.
Use an extra set of parentheses to group the entire assignment together as one argument:
> puts((x,y=1,2))
1
2
But note that this is passing a single list that contains two items. It doesn't make a difference with puts
, but it will for methods that distinguish between lists and individual parameters:
> def foo(a,b) puts "a=#{a},b=#{b}" end
> foo((x,y=1,2))
ArgumentError: wrong number of arguments (1 for 2)
So in that case you need one more piece of punctuation - the splat operator:
> foo(*(x,y=1,2))
a=1, b=2
Interesting, but of little practical relevance, is the fact that once you've doubled the parentheses, you can put the space back if you want:
> puts ((x, y = 1, 2))
1
2
But again, that turns them from argument-wrappers into just an extra expression-wrapper; you could put any number of parentheses around that without changing anything. That means that in the foo
case, the splat operator has to go outside both sets of parentheses:
> foo (*(x,y=1,2))
SyntaxError: (irb):24: syntax error, unexpected tSTAR
> foo *((x,y=1,2))
a=1, b=2
It's generally considered bad style in Ruby to use the parenthesisless form when the first argument itself includes parentheses, however. Depending on your Ruby version you may get a warning about such statements, but even if you don't, it's better to use the fully-parenthesized version (with no space after the method name).
This should work
puts( (x, y = 1, 2) )
puts((x, y = 1, 2))
# >> 1
# >> 2
One set of parentheses for method call, another for decorating assignment as an explicit expression.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With