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}
Update 27 Apr 2009
Fixed a typo, an extra trailing parenthesis, pointed out by Brian Adkins.Trackbacks
Use the following link to trackback from your own site:
http://talklikeaduck.denhaven2.com/trackbacks?article_id=465





The words you put in my mouth were the ones I would have put there myself :)
On the “select{…}.method” thing, it is true that my rule concerns the use of the value returned by the block, not the value returned by select. But surprising, most of the time blocks that return values are used with methods that return values of interest. E.g. I’m almost never interested in the value returned by :each. But the value return by select is almost always useful (and a candidate for further method applications).
I agree with most of this, although returning a value isn’t what I use to determine braces or do end.
It’s a multi-line thing for my, but as you say having an end.function() is really ugly, so that is when I break my multi-line rule.
Hey, that’s a nice idea!
I also think that :
collection.select { | x |
}.some_other_method
looks better than the “do, end” version.