Adam Rackis
Adam Rackis

Reputation: 83358

Ruby multiline block without do end

I’m a beginner in Ruby, so I’m sorry to ask something so simple, but is there anything wrong with this code –

3.upto(9) {
  print "Hello"
  puts " World"
}

or

3.upto(9) { |n|
  print "Hello "
  puts n
}

It works well enough, but most of the code samples I see use the syntax of

3.upto(9) do |n|
  print "Hello "
  puts n
end

is it just the convention to only use curly braces for single statements? Coming from C/C# the first seems more natural to me, but when in Rome!

Upvotes: 25

Views: 21890

Answers (3)

dan-klasson
dan-klasson

Reputation: 14180

There's seamless. From the README:

Python allows you to signal the end of a code block with indentation. Ruby suffers from an extremely verbose and tedious block terminator, "end". Much like Lisps end up with dozens of close-parens, Ruby files that use modules and classes heavily end up with a plethora of "ends" that just aren't necessary.

Write a Ruby file, but skip all the "ends". Line up your code blocks like in Python. Then just call it 'your_file.rbe', require 'seamless', and require 'your_file'. Seamless does the rest.

Should this ever see widespread use? I don't know. But it's pretty fun!

Upvotes: 0

Brian Campbell
Brian Campbell

Reputation: 332736

There is a subtle difference between the two syntaxes. { } are higher precedence than do ... end. Thus, the following will pass bar and a block to method foo:

foo bar do ... end

while the following will pass a block to bar, and the result of that to foo:

foo bar { ... }

So your examples will act the same. However, if you left the parentheses off:

> 3.upto 9 { 
  puts "Hi" 
}
SyntaxError: compile error
(irb):82: syntax error, unexpected '{', expecting $end
3.upto 9 { 
          ^
    from (irb):82
    from :0

> 3.upto 9 do 
    puts "Hi" 
  end
Hi
Hi
Hi
Hi
Hi
Hi
Hi
=> 3

So, { } are more likely to catch you up if you leave off parentheses in Ruby, which is fairly common; for this reason, and because Ruby conditionals and other control constructs all use end as a delimiter, people usually use do ... end for multi-line code blocks that come at the end of a statement.

However, { } is frequently use in places where do ... end would be cumbersome, for instance, if you are chaining several methods together which take blocks. This can allow you to write short, one line little blocks which can be used as part of a method chain.

> [1,2,3].sort{|x,y| y<=>x}.map{|x| x+1}
=> [4, 3, 2]

Here's an example to illustrate this difference:

def foo arg
  if block_given?
    puts "Block given to foo"
    yield arg
  else
    puts "No block given to foo"
    arg
  end
end


def bar
  if block_given?
    puts "Block given to bar"
    yield "Yielded from bar"
  else
    puts "No block given to bar"
  end
  "Returned from bar"
end

irb(main):077:0> foo bar { |arg| puts arg }
Block given to bar
Yielded from bar
No block given to foo
=> "Returned from bar"
irb(main):078:0> foo bar do |arg| puts arg end
No block given to bar
Block given to foo
Returned from bar
=> nil

Upvotes: 52

sepp2k
sepp2k

Reputation: 370102

It's just convention.

Upvotes: 6

Related Questions