A simple coding style for slightly more readable Ruby: symbols as flag arguments.
Use a symbol with a meaningful name instead of true
. This makes it clear what you're doing and is just as terse. For example:
def run(log_it = false)
log_action if log_it
run_action
end
command.run(true) # mysterious use of `true`
command.run(:with_logging) # obvious
The second call to #run is functionally equivalent to the first, because every symbol is a truthy value. But it's a lot easier to read the code with the symbol and understand what the argument means.
The other common pattern I see in Rails is to use an options hash. That call would look like
command.run(:with_logging => true)
If you have a bunch of options, that's fine. When it's just a single optional flag, I prefer passing a symbol with a meaningful name.
Others might say that boolean parameters aren't such a good idea; that you should use two methods instead.
On this particular case that is particularly appropriate since there's already a run_action method.
i've found something similar in some of YUI's apis:
domNode.show("fadeIn"); // same as domNode.show(true);
Greetings,
I like to recommend using Ruby 1.9.2 style hashes along with options hashes as follows:
It's the same as your second version but looks a little cleaner, and starts looking better and better as you get more parameters. It starts to feel like named parameters, which is nice.
-- Morgan
This is slick, I haven't thought about calling it that way before. I also prefer a single optional variable over going the opts = {} route when you only have one option, but I've also run into the 'what does "true" mean in this context?' question when calling it.
I haven't tried this out yet, but I imagine this will work in ActiveRecord:
Thanks for sharing Josh.
I've done
at times. The upside compared to the symbol is that you can use this for non-obvious non-bools as well.
I agree about the problem with boolean parameters. However, I don't know if using a symbol is the answer.
To begin with, that symbol looks awfully like a comment to me. By that, I mean that you could change it without affecting the program. That's because it's never used anywhere else. So, like comments, I think it's an excuse for unclear code.
Then there's the issue of intentionality. At first glance, a reasonable assumption that :without_logging might be useful.
But it's better than a bare boolean, which in this case provides 0 context for what it might do.
I like the style, but I think I'd prefer checking for the symbol in the method.
The problem is that that this also works the same way, rather than turning logging off like you might expect.
Which is one of the nice features within Objective-C, allowing you to encode the names of your parameters as part of the method call itself - it helps increase the readability of the code in my opinion.
@Nick: They must've got this from Smalltalk, where the parameter names are part of the method name. It's pretty nice.
Yes, the named params in Obj-C were lifted directly from Smalltalk-80. Brad Cox based Obj-C heavily on Smalltalk.
And yes, using a symbol instead of true is essentially a comment. But I don't think it's worth worrying about accidentally typing command.run(:without_logging) instead of command.run(:with_logging). I'm not talking so much about API design here as how to make using a badly designed API a little better.
I see what you mean. The canonical example in Rails is
object.children(:reload)
, and even I've used that.Coincidentally, Martin Fowler weighs in on this very subject today: http://martinfowler.com/bliki/FlagArgument.html
I like it. is there a similarly readable technique for passing false?
For someone new to Ruby this will be very irritating. You wonder what kind of value
:with_logging
has and why you can't find it anywhere else. So in my opinion this is -1 for clarity. Therefore I'd prefer @Morgan's idea.@bt: I don't understand why you'd be especially concerned about someone new to Ruby. What values count as true and false is pretty fundamental, and something people pick up quickly. And while using keyword args is nice, there are plenty of APIs that don't work that way.