5

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?

1
  • try without the space puts(x,y = 1,2) Commented Oct 16, 2013 at 12:26

5 Answers 5

12

You have two problems.

  1. 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:

  2. 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).

Sign up to request clarification or add additional context in comments.

Comments

5

This should work

puts( (x, y = 1, 2) )

1 Comment

This will produce a warning because the space between puts and (.
2
puts((x, y = 1, 2))
# >> 1
# >> 2

One set of parentheses for method call, another for decorating assignment as an explicit expression.

Comments

1

puts is a method that takes parameters and prints. In methods, u can set the parameter value to any default value. In ur case its not parallel assignment but setting of default value. If u do

>puts(a, b = 1, 2)
=> undefined local variable or method `a' for main:Object
from (irb):1

but if u set value of 'a', say 'a = 99' and do

 >puts(a, b = 1, 2)
 99
 1
 2
 => nil 

In ruby, if u specify the '()' explicitly, u cant specify a space between the method name and opening (

 def hi(x,y,z)
    p x
    p y
    p z
 end
 => nil 

 2.0.0p247 :015 > hi(1,2,3)
 1
 2
 3
 => 3 

 2.0.0p247 :016 > hi (1,2,3)
 SyntaxError: (irb):16: syntax error, unexpected ',', expecting ')'
 hi (1,2,3)
  ^
from /home/prasad/.rvm/gems/ruby-2.0.0-p247/gems/railties-   4.0.0/lib/rails/commands/console.rb:90:in `start'
from /home/prasad/.rvm/gems/ruby-2.0.0-p247/gems/railties-4.0.0/lib/rails/commands/console.rb:9:in `start'
from /home/prasad/.rvm/gems/ruby-2.0.0-p247/gems/railties-4.0.0/lib/rails/commands.rb:64:in `<top (required)>'
from bin/rails:4:in `require'
from bin/rails:4:in `<main>'

 2.0.0p247 :017 > hi 1, 2, 3
 1
 2
 3
 => 3 

Comments

1

puts is a method, and you are trying to pass the return value of = (an assignment) to it. To do so, you have to wrap it in two pairs of parentheses:

puts((x, y = 1, 2))

However, this leads to confusing code and should be avoided.

Instead do it in two steps, it's easier and cleaner:

x, y = 1, 2
puts x, y

Furthermore, you can remove the puts line without breaking functionality.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.