ConorSheehan1
ConorSheehan1

Reputation: 1725

Ruby method call using round brackets throwing syntax error

I'm having some trouble understanding why I can't call select with round brackets.

a = [1,2,3]
a.select {|v| v.is_a?(Integer)}  # works
a.select({|v| v.is_a?(Integer)}) # syntax error, unexpected '|', expecting '}

As far as I can tell select is a regular method.

Array.method_defined? :select # true
Array.method_defined? :is_a?  # true

I though round brackets are optional for methods in ruby.
In the case below round brackets make no difference.

a.reverse() == a.reverse #true

I'm using ruby 2.2.1.
Any ideas?

Upvotes: 0

Views: 873

Answers (3)

Kris
Kris

Reputation: 19938

You cannot pass a block with such a synatx, you would have to do something like this:

a.select(&lambda { |v| v.is_a?(Integer) })

but normally you would just do

a.select { |v| v.is_a?(Integer) }

which is the same as

a.select() { |v| v.is_a?(Integer) }

i.e the block is outside the method parameters.

You could also use the 'stabby' lambda syntax:

is_a_integer = ->(v) { v.is_a?(Integer) }
a.select(&is_a_integer)

So if you want to pass a block as an argument you need to prefix with &, but usually you would have the block outside the parameters for atheistic reasons.

Also notice the difference between these to method signatures and the way they are called:

def call(&block)
  yield
end

call { 1 } # => 1

call(lambda { 1 }) # => ArgumentError

call(&lambda { 1 }) # => 1

and

def call(block)
  block.call
end

call { 1 } # => ArgumentError

call(lambda { 1 }) # => 1

call(&lambda { 1 }) # => ArgumentError

This is because lambda (and Procs) are objects hence we can do #call to evaluate them, but blocks are not and can be evaluated using the yield keyword. There is more information in this blog post.

lambda { 1 }.class # => Proc

Upvotes: 4

axiac
axiac

Reputation: 72186

With or without parenthesis, Array#select doesn't accept any regular arguments. It, however accepts a block argument but the blocks associated with a method call are always placed after the parenthesis, not inside them.

Consequently, the call:

a.select {|v| v.is_a? Integer }

can also be written with parenthesis as:

a.select() {|v| v.is_a? Integer }

Upvotes: 1

Puhlze
Puhlze

Reputation: 2614

Round brackets are a way to pass arguments to a method while the squiggly brackets (or do/end) are a way to pass a block to a method. They are not interchangeable.

Squiggly brackets can also be used to create a hash in ruby, which can cause some confusion.

Some ruby methods can take arguments and a block in which case you can use round brackets before the squiggly brackets: E.G.

open("ChangeLog") { |f|
    f.slice_before(/\A\S/).each { |e| pp e }
}

Upvotes: 2

Related Questions