13
JUN2006
Do I Need (These Parentheses()?)
If you came to Ruby via the Learn to Program book or just don't yet have a consistent set of rules for when you do and don't need parentheses in Ruby code, this post is for you.
I have nothing against Learn to Program, just to be clear. A member of my family is learning Ruby from it and it's going pretty well. I recommend it. However, Chris is a little inconsistent with his use of parentheses in the code samples, and worse, he doesn't really give you a good set of rules to decide when to make the choice. No problem. Let me give you the rules.
I'm a chess player. In learning chess, you really go through two phases. First, you learn the rules of strategy. These will make you good because the rules are designed to help you avoid common mistakes. Now, to get great, you go through the second phase: learning when to break the strategy rules. Ruby is exactly the same.
Here's the only rule of strategy you need to learn to get good: methods need parentheses around their arguments.
So you want to write:
def my_method(args, go, here) # not def my_method args, go, here
# ...
end
and:
my_method(args, go, here) # not my_method args, go, here
I'm serious. That's it. You're good now. Congratulations! Wasn't that easy? If you've had enough learning for one post, call it an early day and be secure in the fact that you are now knowledgeable in the Way of the Parentheses. If you have some energy left, read on and I'll make you great…
First, let's talk about what's not a method call. Mainly if
and while
are keywords in Ruby and they don't require parentheses. When you add them, we laugh behind your back and call you a Java programmer. So it's:
while condition # not while (condition)
# ...
end
and:
if condition # not if (condition)
# ...
end
OK, here's another easy one. I said the rule was, "…need parentheses around their arguments." If we take that literally, we can figure out the next exception: no arguments means parentheses aren't needed. So it's:
"james".capitalize # not "james".capitalize()
and:
[ ].empty? # not [ ].empty?()
Now, because you're probably using them often, we will relax the rules on puts()
and p()
. You can leave them off those calls, as long as you are following the rest of these rules. That lets us to write:
puts "Something to print..." # not puts("Something to print...")
or even:
p rand(100) # not p(rand(100))
One last exception. The question methods read very prettily without parentheses and beautiful code is always a good goal, so drop them in simple conditionals with just one question and argument. For example:
if obj.is_a? Whatever # not if obj.is_a?(Whatever)
# ...
end
Beware of that last one though. If the condition is getting complicated, add the parentheses:
if obj.is_a?(Whatever) || obj.is_a?(WhateverElse)
# ...
end
Finally, beware of the gotchas. If you have a bunch of &&
s and ||
s in a conditional, use parentheses to set the order just as you would a math statement. Also, watch out for this:
puts((1 +2) * 3) # not puts (1 + 2) * 3
Comments (18)
-
acrylic June 13th, 2006 Reply Link
Here is a rule I follow:
When you are calling a method without an explicit receiver (like a method in your class) and it takes no parameters, use parentheses or add an explicit receiver (
self
). It is very confusing sometimes if you do not.class Foo def some_method blah() # not blah self.blah # careful, won't work if #blah is private end def blah ... end end user_input = gets() # not gets user_input = STDIN.gets
-
Although I agree with these rules in general, it's interesting to point out that Rails (specifically the Rails documentation) seems adamantly against parentheses, (and braces on hash tables...)
Although it makes their code almost read like English, it can be hard to understand what exactly is going on if you're new to Ruby (it seems that quite a bit of Rails programmers jump right in knowing no Ruby beforehand)
Any insight?
-
Yeah, Rails has a lot to answer for in this regard, IMHO, although at the same time I've written DSL type stuff myself that's just looked better without parens. Maybe it's just because like null said, a lot of Rails programmers see Rails before Ruby. Ho hum…
-
These rules are my opinion of what's correct. Obviously, others, including the Rails core team, may not agree with me 100%. I try to worry more about whether I am doing things right.
Also, I'm pretty sure Ruby herself agrees with me:
$ ruby -w -e 'puts rand 100' -e:1: warning: parenthesize argument(s) for future version 48
-
-
My only rule of thumb is whenever Ruby or I have problems parsing a method call, I add parentheses. It works pretty well.
-
Given that I've been doing a lot of Rails lately and that I rather like dropping the parenthesis when possible, the rules I tend to follow are much in line with your own, however, I also tend to think of whether or not my method call is a statement, or a request for a resource. For instance:
# link_to() is a statement: you want the end result, not access to a resource link_to "Link Text", :action => "some_action" # find() is accessing a resource User.find(:first, :conditions => ["username = ?", username])
I always use parenthesis in documentation, without exception.
-
Last example could mention that
puts((1 +2) * 3)
and
puts ((1 + 2) * 3)
and
puts (1 + 2) * 3
work out OK
but
puts(1 + 2) * 3
is not working (by default).
Considering
puts
' speciality I'm not even sure which one from the first three is the best. -
Your rules seem to say
obj.my_attr=(0)
is preferred to
obj.my_attr= 0
I don't think I agree.
-
Jim: Very good point there. I treat equal method accessors as operators and I only use parenthesis for those as needed. Good catch.
-
Similar to Jim's comment, if you're going to update your suggestions, you might want to include the
#[]
and#[]=
methods as no-paren aspects, also.-
Again that falls into the operators category with me, so yes we don't need parenthesis with those.
-
-
-
I grown used to not using parentheses around args in method definitions or when calling methods is just the habit but now I find easier to read, so my rule is:
I use parenthesis only when there is ambiguity.
I find it liberating and aesthetically pleasing not having all those parenthesis and curly braces.
The downside is that I find it harder to adjust to other people's style when collaborating.I agree with James H: I always use parenthesis in documentation because is the most common habit.
-
Is there any benefit to any of this? Macario Ortega got this right.
I use parenthesis only when there is ambiguity…
The minimal use of params should be to disambiguate expressions in the language's syntax i.e the parser. Additional use should aid human clarification.
Human clarification cannot be determined by this (or any other) finite set of rules. The best effort to improve clarity is by observation and critical thinking.
Ruby gives us the freedom to express a concept in multiple forms. Rules like these extinguish thinking about clarity, do they not?
-
Obviously, programmers will reach a point where they can distinguish which "rules" to follow in which scenarios, eventually. Until then, they exist to give us guidelines that are meant to help us.
I'm very for freedom and critical thinking, but I also see a lot of new programmers writing Ruby that doesn't look like Ruby. That hinders their ability to participate in the community and get help, so there are tradeoffs.
-
-
Hi James. Listening to you on the Ruby Rogues… Any chance that your rules about using parentheses to make the code a bit more clear somewhat depends on one's tools. Specifically, I use RubyMine and I find that having the method args in a different color than the method name seems quite sufficient for clarity.
-
That's a fair point. I suppose the environment does play a role.
However, is your code still going to have the same level of readability when viewed in an environment without this feature?
My editor also colors the arguments, but it doesn't feel sufficient to me. I guess that just proves it's a matter of taste.
-
-
I posted the question on StackOverflow as to when the parser requires parens.
The answer is almost never. My approach to parens for methods arguments and definitions is to add them when they make the syntax more clear, and for definitions, I already see the indenting to the left, blank lines or comments before. My approach for parens on method definitions is to use them when needed, which has not happened yet, given the limited cases where it's needed.
-
I've actually changed tactics quite a bit since this post.
Nowadays I pretty much use this rule: if I might use the return value someday, I add parentheses. This reduces friction when I am refactoring, since I won't need to stop add parentheses so I can chain on another method or something. Reducing the friction to refactoring means that I refactor more. That's almost always a good thing, in my opinion.