TLDR

  • In Ruby, blocks in braces, { ... }, bind stronger than in do ... end do
  • Rule of thumb
    1. Use { ... } for single-line blocks
    2. do ... end for multi-liners

Try Guess the Output

Answers in section “Precedence in Execution”

arr = [1, 2, 3]
a = arr.map { |num| num * 2 }
b = arr.map do
  |num| num * 2
end

puts a # => ???
puts b # => ???
arr = [1, 2, 3]
puts arr.map { |num| num * 2 } # => ???
puts arr.map do
  |num| num * 2
end # => ???

What is Block in Ruby

In Ruby, a (code) block is a piece of code that takes arguments. A block can NOT “survive” on its own, UNLESS it is attached to methods, or in the form of proc or lambda.

# Two ways to wrap a block in Ruby
# They will cause errors if put like these
# 1. { ... }
{ puts 1 } # gets "SyntaxError"
# 2. do ... end
do puts 1 end # gets "SyntaxError"
def some_method
  yield
end

# Good; these will not cause SyntaxError
some_method { puts 1 }
proc_print_one = proc { puts 1 }
lambda_print_one = lambda { puts 1 }

Read more about the difference between proc and lambda in my blog post Proc & Lambda in Ruby!

Precedence in Execution

Per documentation in Ruby-Doc.org, { ... } blocks have priority below all listed operations, but do ... end blocks have even lower priority.

  • No difference in terms of output, as all gets executed before printed
arr = [1, 2, 3]
a = arr.map { |num| num * 2 }
b = arr.map do
  |num| num * 2
end

puts a # => [2, 4, 6]
puts b # => [2, 4, 6]
  • The following #maps are interpreted differently in Ruby
    • puts arr.map { ... } equals puts(arr.map { ... }), but
    • puts arr.map do ... end are actually puts(arr.map) do ... end
arr = [1, 2, 3]
puts arr.map { |num| num * 2 } # prints the following
# 2
# 4
# 6
puts arr.map do
  |num| num * 2
end # => #<Enumerator:0x00007fb34d8d40c0>

See Precedence for the comprehensive list of precedence.

References