Early Steps

My content targeted at the newer Rubyists among us.

13

JUN
2006

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)
  1. acrylic
    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
    
    1. Reply (using GitHub Flavored Markdown)

      Comments on this blog are moderated. Spam is removed, formatting is fixed, and there's a zero tolerance policy on intolerance.

      Ajax loader
  2. null
    null June 13th, 2006 Reply Link

    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?

    1. Reply (using GitHub Flavored Markdown)

      Comments on this blog are moderated. Spam is removed, formatting is fixed, and there's a zero tolerance policy on intolerance.

      Ajax loader
    2. Sudo Nimm
      Sudo Nimm June 13th, 2006 Reply Link

      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…

      1. Reply (using GitHub Flavored Markdown)

        Comments on this blog are moderated. Spam is removed, formatting is fixed, and there's a zero tolerance policy on intolerance.

        Ajax loader
    3. James Edward Gray II
      James Edward Gray II June 13th, 2006 Reply Link

      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
      
      1. Reply (using GitHub Flavored Markdown)

        Comments on this blog are moderated. Spam is removed, formatting is fixed, and there's a zero tolerance policy on intolerance.

        Ajax loader
  3. Simen
    Simen June 15th, 2006 Reply Link

    My only rule of thumb is whenever Ruby or I have problems parsing a method call, I add parentheses. It works pretty well.

    1. Reply (using GitHub Flavored Markdown)

      Comments on this blog are moderated. Spam is removed, formatting is fixed, and there's a zero tolerance policy on intolerance.

      Ajax loader
  4. James H
    James H June 15th, 2006 Reply Link

    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.

    1. Reply (using GitHub Flavored Markdown)

      Comments on this blog are moderated. Spam is removed, formatting is fixed, and there's a zero tolerance policy on intolerance.

      Ajax loader
  5. Harry
    Harry July 12th, 2006 Reply Link

    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.

    1. Reply (using GitHub Flavored Markdown)

      Comments on this blog are moderated. Spam is removed, formatting is fixed, and there's a zero tolerance policy on intolerance.

      Ajax loader
  6. Jim
    Jim July 17th, 2006 Reply Link

    Your rules seem to say

    obj.my_attr=(0)
    

    is preferred to

    obj.my_attr= 0
    

    I don't think I agree.

    1. Reply (using GitHub Flavored Markdown)

      Comments on this blog are moderated. Spam is removed, formatting is fixed, and there's a zero tolerance policy on intolerance.

      Ajax loader
    2. James Edward Gray II
      James Edward Gray II July 17th, 2006 Reply Link

      Jim: Very good point there. I treat equal method accessors as operators and I only use parenthesis for those as needed. Good catch.

      1. Reply (using GitHub Flavored Markdown)

        Comments on this blog are moderated. Spam is removed, formatting is fixed, and there's a zero tolerance policy on intolerance.

        Ajax loader
    3. Gavin Kistner
      Gavin Kistner August 29th, 2006 Reply Link

      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.

      1. Reply (using GitHub Flavored Markdown)

        Comments on this blog are moderated. Spam is removed, formatting is fixed, and there's a zero tolerance policy on intolerance.

        Ajax loader
      2. James Edward Gray II
        James Edward Gray II August 29th, 2006 Reply Link

        Again that falls into the operators category with me, so yes we don't need parenthesis with those.

        1. Reply (using GitHub Flavored Markdown)

          Comments on this blog are moderated. Spam is removed, formatting is fixed, and there's a zero tolerance policy on intolerance.

          Ajax loader
  7. Macario Ortega
    Macario Ortega July 10th, 2009 Reply Link

    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.

    1. Reply (using GitHub Flavored Markdown)

      Comments on this blog are moderated. Spam is removed, formatting is fixed, and there's a zero tolerance policy on intolerance.

      Ajax loader
  8. franco
    franco July 26th, 2011 Reply Link

    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?

    1. Reply (using GitHub Flavored Markdown)

      Comments on this blog are moderated. Spam is removed, formatting is fixed, and there's a zero tolerance policy on intolerance.

      Ajax loader
    2. James Edward Gray II
      James Edward Gray II July 26th, 2011 Reply Link

      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.

      1. Reply (using GitHub Flavored Markdown)

        Comments on this blog are moderated. Spam is removed, formatting is fixed, and there's a zero tolerance policy on intolerance.

        Ajax loader
  9. Justin Gordon
    Justin Gordon August 28th, 2012 Reply Link

    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.

    1. Reply (using GitHub Flavored Markdown)

      Comments on this blog are moderated. Spam is removed, formatting is fixed, and there's a zero tolerance policy on intolerance.

      Ajax loader
    2. James Edward Gray II
      James Edward Gray II August 28th, 2012 Reply Link

      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.

      1. Reply (using GitHub Flavored Markdown)

        Comments on this blog are moderated. Spam is removed, formatting is fixed, and there's a zero tolerance policy on intolerance.

        Ajax loader
  10. Justin Gordon
    Justin Gordon February 7th, 2013 Reply Link

    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.

    1. Reply (using GitHub Flavored Markdown)

      Comments on this blog are moderated. Spam is removed, formatting is fixed, and there's a zero tolerance policy on intolerance.

      Ajax loader
  11. James Edward Gray II
    James Edward Gray II February 7th, 2013 Reply Link

    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.

    1. Reply (using GitHub Flavored Markdown)

      Comments on this blog are moderated. Spam is removed, formatting is fixed, and there's a zero tolerance policy on intolerance.

      Ajax loader
Leave a Comment (using GitHub Flavored Markdown)

Comments on this blog are moderated. Spam is removed, formatting is fixed, and there's a zero tolerance policy on intolerance.

Ajax loader