1
  • 1 parenthesis:

    print ( (1..10).collect do |x| x**2 end )
    SyntaxError: compile error
    

    More details:

    (irb):1: syntax error, unexpected kDO_BLOCK, expecting ')'
    print ( (1..10).collect do |x| x**2 end )
                              ^
    (irb):1: syntax error, unexpected kEND, expecting $end
    print ( (1..10).collect do |x| x**2 end )
                                           ^
    
  • 2 parentheses:

    print (( (1..10).collect do |x| x**2 end ))
    149162536496481100=> nil
    

I understand the difference between print (a) do <...> and print(a) do <...>. But what is the difference in my case? Why are two parentheses not the same as one?

egor7
  • 4,678
  • 7
  • 31
  • 55

2 Answers2

1

TL;DR

The reason adding extra parentheses "works" is because nested parentheses provide higher precedence to the innermost expression. This disambiguates the tokens for the parser, and allows the statement to be properly evaluated as an expression rather than a method argument.

Analysis

It has to do with the binding precedence of the keywords. Braces have higher precedence than the do/end keywords, so this will work:

print ( (1..10).collect { |x| x**2 } )

because it's interpreting the parenthesized expression as an expression boundary, rather than as bounding a method argument.

You could also do:

print( (1..10).collect do |x| x**2 end )

because here the parentheses bound an argument, rather than separate an expression.

Todd A. Jacobs
  • 81,402
  • 15
  • 141
  • 199
  • You answer is related to the known problem: `print (a) do <...>` vs `print(a) do <...>`. Not to the question I've asked. – egor7 Jun 24 '12 at 17:15
  • @egor If you give the parser ambiguous forms, it gives you ambiguous results. `print (1..10).collect do |x| x**2 end` returns an enumerator, not an array. Adding more parentheses forces another layer of expression evaluation, so it "works" because you're giving the expression higher precedence. Why fight the parser? – Todd A. Jacobs Jun 24 '12 at 17:21
  • The question is not about the case with no parentheses at all. I use 1 and 2 parenthesis. Why ruby interprets them different? – egor7 Jun 24 '12 at 17:31
0

Use this:

print((1..10).collect do |x| x**2 end)

And better this:

print((1..10).collect do |x|; x**2; end)

Always remove the space between a method name and parenthesis. It is one of ruby interpreter's syntax analysis. If you put both space and parenthesis, ruby sometimes is not able to correctly interpret.

When you put separate lines of code in one line, use ; to separate (because do end block is supposed to be placed in separate lines)

SwiftMango
  • 15,092
  • 13
  • 71
  • 136
  • 1
    There's no syntactical reason a `do ... end` block should be placed on separate lines. It's just convention (and not a universal one; see http://stackoverflow.com/a/5917056/1364726 ). – echristopherson Jun 24 '12 at 20:21
  • @echristopherson Yes it is not strictly should be in separate lines, but it is suggested to. And my point is to put semi-colon there because it will avoid problems, especially if you call a method using space or put more than one line of code there – SwiftMango Jun 24 '12 at 21:28
  • I don't see how it would make any difference. Smells a little superstitious. – echristopherson Jun 24 '12 at 23:52