This post originated from an RSS feed registered with Ruby Buzz
by Rick DeNatale.
Original Post: Ruby Blocks, do or brace?
Feed Title: Talk Like A Duck
Feed URL: http://talklikeaduck.denhaven2.com/articles.atom
Feed Description: Musings on Ruby, Rails, and other topics by an experienced object technologist.
Conventional wisdom in Ruby is to use do/end to delimit blocks which contain more than one line of code, and braces for one-line blocks. I've always tended to loosely follow this advice.
Thanks to ruby-talk, I just became aware of Jim Weirich's suggestion to use braces for blocks when the value is being used, and do/end for blocks which are primarily sequences of statements. Jim actually posted this over three years ago, and Joe O'Brien brought it up more recently.
On the whole, I like this idea and will probably adopt it to tune my use of do/end vs. braces.
But don't all blocks return a value?
Here's Jim's prescription:
Use { } for blocks that return values
Use do / end for blocks that are executed for side effects
For the pedantic minded, it's true that all Ruby blocks actually return values. Every Ruby statement and expression, returns a value. Some folks have used this to object to the suggestion, or at least question it.
At the risk of putting words in Jim's mouth, I believe that he's really talking here about the use/non-use of the value of the block. If you use the value of the block then tilt more to using braces. If the value is discarded then lean towards do/end.
Why I Like this idea
Visually {x + 7} feels more like ( x + 7) than do; x + 7; end does.
Related Things
I've always been slightly uncomfortable writing code like this:
collection.select do | x |
something
something_else
end.some_other_method
Instead I think that:
collection.select { | x |
something
something_else
}.some_other_method
Just looks better to my eye, despite the multi-line block body.
When I first started writing this, I was thinking that this was an example of Jim's style, but it really isn't. First of all the value of the block is being used, but not directly in the code we're looking at. It's being used internally by the select method.
Now I don't think that you should use braces for any block passed to a method like select, even though the value is being used there.
Second, the value we're using here isn't the value of the block but the value of the select method call.
That said, I still like using the braces in this case.
Another tension
Keep in mind that you aren't completely free to substitute braces for do/end. Sometimes you need to bow to Ruby's precedence rules. Generally in Ruby if something has both a word and a symbolic representation, e.g. {} vs do/end, || vs or, etc. The symbolic version has higher syntactic precedence than the word version. This comes up at times, particularly when you are using a DSL in it's 'natural' mode and not using 'unnecessary' parentheses. For example in Rake:
description 'pickup up the leaves'
task :rake => pre_raking_tasks do
#code to rake the leaves
end
Works as expected, but:
description 'pickup up the leaves'
task :rake => pre_raking_tasks {#code to rake the leaves}
Won't because it actually means
description 'pickup up the leaves'
task :rake => (pre_raking_tasks {#code to rake the leaves})
The block is given to the pre_raking_tasks invocation rather than the task invocation. So you either need to use do/end or parenthesize explicitly:
description 'pickup up the leaves'
task(:rake => pre_raking_tasks) {#code to rake the leaves})