Confused about when to use parentheses or blocks in Ruby

On the surface, Ruby seems to be very similar to other objects like Java, Php, C, etc.

but things get a little weird when we start to run into blocks.

for example this works

(0...8).max()
 => 7 

      

But it is not

(0...8).map(puts "hello world")
hello world
ArgumentError: wrong number of arguments(1 for 0)

      

In contrast, the map method accepts no arguments, but blocks, so passing the replacement ()

using to {}

fix the error.

(0...8).map{puts "hello world"}
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
 => [nil, nil, nil, nil, nil, nil, nil, nil] 

      

And then there are some methods that must take both blocks and arguments

8.downto(1){puts "hello world"}
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
 => 8 

      

I have a problem if I have to use ()

, {}

or both methods. On what basis is this decided?

  • Is it fixed on a per method basis and I just remember what the method takes (blocks or parameters)?
  • Or is there some other logical reasoning that determines if a method takes blocks {}

    or params ()

    ?

Please help me understand

+3


source to share


3 answers


The parentheses after method calls are actually optional.

(0...8).map{puts "hello world"}

equivalent to (0...8).map() {puts "hello world"}

This way you don't really replace them.

The acceptance of blocks is entirely method dependent, they can be specified in the method declaration:

def method(param, &block)
  block.call
end

      



which will allow you to access the block as a variable from the method and is called, for example, via block.call

.

They can also be used implicitly using the keyword yield

:

def method(param)
  yield
end

      

Therefore, you need to refer to the API docs to be sure what is accepted or not.

+6


source


It should be documented in the API of this method.



If there is a method that takes an argument, the block is usually optional - in which case it is used to "refine" the way the method works - for example Hash.new

, which can take an argument (the default hash value) and the block that is used for smart operations during initialization key values. But most of the methods that require a block do not take an argument, eg. Array#select

or Array#map

.

+2


source


You use parentheses to pass arguments to a function. It is always a comma-separated list of objects. They can be the result of a function, but they don't have to. The function they result in will always be called only once.

Example:

x = Array.new
=> []
x.push(2)
=> [2]
x.push(7.modulo(4))
=> [2,3]

      

You use blocks to pass functional behavior to a method. Typically, these functions are designed to be called with many different arguments or a specific number of times. puts "hello world"

is a function that prints something, but only returns nil

. Thus, you will almost never try to use this as an argument to a function (as you would pass to nil

that function), but usually you would pass it as a function block so that it could be called multiple times.

Most of the time you will want to have a block that you pass to a function, use arguments so that it actually does something different for each call.

Example:

(0..8).each{ |number| 
  if number.odd?
    puts "#{number} is odd"
  end
}
=> 1 is odd
=> 3 is odd
=> 5 is odd
=> 7 is odd
=> => 0..8

      

+2


source







All Articles