9

can anybody explain why the following code aborts with an error

irb(main):186:0> print ((1..10).collect do |x| x**2 end)
SyntaxError: (irb):186: syntax error, unexpected keyword_do_block,
expecting ')'
print ((1..10).collect do |x| x**2 end)
                         ^
(irb):186: syntax error, unexpected keyword_end, expecting $end
print ((1..10).collect do |x| x**2 end)
                                      ^
        from /usr/bin/irb:12:in `<main>'

whereas following code with the same functionality works as expected ?

irb(main):187:0> print ((1..10).collect { |x| x**2 })
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]=> nil

I did believed curly-braces "{ }" can substitute "do end" arbitrarily at block definition.

I know I can "fix" the first call by omitting a space between print method and the first parenthesis, but I'm interested in an explanation why it behaves different.

Andrew Grimm
  • 78,473
  • 57
  • 200
  • 338
S1ackman
  • 91
  • 2
  • See [similar question premise](http://stackoverflow.com/questions/2122380/using-do-block-vs-brackets) also. – Zabba May 30 '11 at 18:20
  • This is a duplicate of [Ruby Block Syntax Error](http://StackOverflow.Com/q/6854283/), [Code block passed to `each` works with brackets but not with `do`-`end` (ruby)](http://StackOverflow.Com/q/6718340/), [Ruby multiline block without `do` `end`](http://StackOverflow.Com/q/3680097/), [Using `do` block vs brackets `{}`](http://StackOverflow.Com/q/2122380/), [What is the difference or value of these block coding styles in Ruby?](http://StackOverflow.Com/q/533008/) and [Ruby block and unparenthesized arguments](http://StackOverflow.Com/q/420147/). – Jörg W Mittag Jul 28 '11 at 08:17
  • @AndrewGrimm: `blocks` is an ambiguous tag that does not help get this question answered. There are fewer than 200 questions tagged with `blocks` and only a handful address Ruby blocks. – coreyward Sep 21 '11 at 00:23
  • @coreyward: There are 71 questions tagged ruby and block, and 56 tagged ruby and blockS (and only one of those overlap). – Andrew Grimm Sep 21 '11 at 00:30

2 Answers2

13

The difference is precedence:

# Equivalent to puts( (1..10).map { |i| i*2 } )
> puts (1..10).map { |i| i*2 }
2
4
6
8
10
12
14
16
18
20
 => nil 

# Equivalent to puts( (1..10).map ) { |i| i*2 }
> puts (1..10).map do |i| i*2 end
#<Enumerator:0x928f24>
 => nil 

In the first case, the block is passed to map, and everything works properly. In the second case, the block is passed to puts, which doesn't do anything with it. map doesn't receive a block and just returns an enumerator.

As for the syntax error, if you remove the space between print and ( everything works ;)

The difference is whether ruby is treating your parentheses as method argument delimiters, or whether it's a generic statement grouping. I'm not sure of the exact difference there but it's subtle and annoying

Gareth
  • 133,157
  • 36
  • 148
  • 157
0

There is an ultimate answer already on SO.

Unfortunately this is definitely not a good demonstration of least surprise philosophy behind Ruby.

Community
  • 1
  • 1
David Unric
  • 7,421
  • 1
  • 37
  • 65