user2399453
user2399453

Reputation: 3081

Parenthesis for arguments before blocks

I notice that I need to put parenthesis around arguments I pass to a Ruby method before the block. Wat is the reason for that? Boiling down to the smallest example to illustrate what I mean:

def test a
   yield 100
end

test 50 { |x| x*x + 2 } # Gives an error in irb!

test(50) { |x| x*x + 2 } # Gives no error!

I didn't understand why Ruby complains about the first case. The error is along the lines of:

SyntaxError: compile error
(irb):18: syntax error, unexpected '{', expecting $end

Upvotes: 2

Views: 115

Answers (4)

the Tin Man
the Tin Man

Reputation: 160551

Ruby doesn't know what you want to do with the block.

When Ruby sees:

test 50 { |x| x*x + 2 } # Gives an error in irb!

It thinks that the block is attached to 50, which is why you get the error.

When you put 50 in parenthesis, Ruby knows that the block is not binding to 50.

test(50) { |x| x*x + 2 } # Gives no error!

For sanity, 99.9% of the time I put the parameters inside parenthesis. I don't like having to remember the rules for binding and that ensures that Ruby will do the right thing. Also, the parenthesis help us see what are the parameters, which aids in debugging.

Upvotes: 1

August
August

Reputation: 12558

Here's an example of the possible ambiguity that would arise:

def foo(val = "default", &block)
  # ...
end

Both hash and block literals are created using { ... }

So if you call foo {} - Are you passing an empty hash to the val parameter (with block becoming nil), or are you passing an empty block to the block parameter (with val becoming "default")?

Upvotes: 3

Mark Reed
Mark Reed

Reputation: 95242

This is related to the fact that {...} sometimes delimits a block and sometimes a Hash literal. Disambiguating those two uses has some odd side-effects.

If you use do...end, it works without the parentheses:

test 50 do |x| x*x + 2 end

Upvotes: 2

tagCincy
tagCincy

Reputation: 1599

When using the block notation, the block is run against the value to the immediate left of the opening {. So in your first example, you are attempting to pass 50 { |x| ... } into the test method. Since 50 is not an Enumerable object, you are getting an error.

Upvotes: -2

Related Questions