Parentheses in Ruby

I’ve been doing a lot of “heart” and “mind” posts lately, and “code” is starting to feel neglected. If you’re not a programmer, feel free to give this one a miss.

I put off writing this post til the last minute because I want to talk about parentheses in Ruby, and I’d like to give you a definitive “do this” answer, but the reality is I just don’t know, so I’m gonna throw out some thoughts and let you guys tell me what you think.

Ruby Makes Parentheses Optional

Okay, that’s not news. But a lot of people come to Ruby from languages where parens are required, and they see that they’re optional in Ruby, and so they keep them in out of habit. And then they complain that Ruby is dumb for not having first-class functions.

What is often overlooked here is that optional parens are important. Matz chose to sacrifice first-class functions just so he could make parentheses optional. So when I started programming in Ruby, I made an effort to eschew them when possible. Now, “optional” means optional–it doesn’t mean banned and it doesn’t mean required. So there’s room for wiggle here.

Some Strong Styles Have Emerged

There are some very strong idioms that have emerged, however. Well, mainly just one: Never use empty parens. This is actually two rules: never put parens at the end of a method definition if the method takes no arguments, and never use parens when sending a message that takes no arguments. There’s a lot of really good reasons for doing this, and I won’t go into them here.

Generally Favoring Parens

I know some smart programmers who favor parens in ruby. Their general argument is simply “it makes the code more readable”.

My experience has been that this argument is indistinguishable from “it makes the code look like the other languages I’ve spent years learning to read”. This is not necessarily wrong. I think both styles have tradeoffs, and there’s a mental cost to be paid to learn to read a new style. Since this cost has to be paid up front, the tradeoff is really imbalanced in the short-term. But is this a false economy in the long run? I’m asking because I don’t know.

Generally Eschewing Parens

On the far other side of the spectrum lies “Seattle.rb style”. Josh Susser originally coined the term “Seatttle style” to mean “not using parens in method definitions”, but Ryan Davis and Seattle.rb have taken it and run with it to mean “never use parentheses unless the compiler requires it”.

I spent a couple weeks experimenting with this style. It definitely had an effect on my code. I never did get to where I like omitting parens from method definitions, and maybe I am subject to my own argument above about embracing the tradeoff. One thing I did find, however, was that trying to avoid parens everywhere else had a profoundly rewarding effect on how I felt about my code. The original argument from Matz about making parens optional was that parens are often just noise, and getting rid of this noise is important.

Parens and Readability

When I talked about this with the rest of the Ruby Rogues, I quickly found myself in a 3-against-1 battle (Katrina wasn’t available). Josh made the argument that omitting parens decreases readability. You have to read this entire line of code to know when the first method call is actually done:

puts array.delete hash.fetch :foo

And I have to agree. That line of code is horrible.

But… it’s not the lack of parens that make it horrible. That line of code is horrible all by itself. I don’t think this is really any better:

puts array.delete(hash.fetch(:foo))

(Another strong convention in Ruby is to never use parens with calls to puts; otherwise another layer of parens could be added, but they would be gratuitous.)

Now, some programmers will find that line of code more readable. My point is that this is a problem. The line looks a bit more comforting, but you still actually have to read the whole line to know what’s happening. This line is doing two manipulations on unrelated primitives followed by a side effect call to puts. This line desperately needs some intention-revealing variable, methods, and selectors.

I see code like this all the time in parenful code. It sort of gets a pass with the parens stuck on. We say “yeah, this could be refactored, but it’s readable enough for now.”

But scroll back up to the version without parens. That line is unforgiveable. It has to go.

How valuable is that? I’m asking; I feel like it’s a lot, but I had to spend a few weeks learning to read a whole new style before I got that value. So I don’t know the answer. I don’t if it’s worth it. What I do know is that by eschewing parens, I never ever write lines like the above. The code just won’t let me. It bugs me, and I refactor it, and then my code feels better to look at, and the whole program becomes much more readable. That’s immensely valuable to me. But I don’t know how to communicate that it’s worth the trouble–or even if it’s worth it at the end of the day.

Readability For Other Developers

Another good question is if one developer hasn’t learned this style, and another one has, should parens be the default to maximize readability? I grind my teeth whenever people start making “lowest common denominator” arguments because it’s really hard sometimes to see the line between “this is overcomplicated” and “let’s do something more stupid because it’s easier”.

So part of the experiment this week has been paying attention to how my coworkers react to my code. It’s hardly been a scientifically rigorous study, but given a sample size of one week and two code reviews, I have one data point. It comes from a coworker who strongly favors parentheses, but has been tolerant of my style. His exact words were:

“Your code is a pleasure to read.”

I am confident that he was not talking about my parenthesis usage, but rather about the clean, refactored, expressive code that resulted from me not liking the way some lines of code looked without parens stuck on.

It’s hardly a conclusive argument, but it’s one that encourages me to continue researching. I’m not ready to stand up and proclaim that parentheses are nothing but noise that covers up code smells, but I am giving serious thought to secretly believing it. 🙂

Weirich-Style Kung Fu

A hybrid style is emerging from these discussions, and it’s structurally based on “The Weirich Rule”, which is about blocks rather than parentheses, but the similarities are definitely there and I find the analogy appealing. In Ruby you can write blocks with braces or with do…end; the Weirich Rule states that if the block returns a value, using braces signals that intent to the reader. If the block exists for its side effects, using do…end signals this intent.

A Weirich-inspired rule for parentheses, then, look like this:

If you care about the return value, send the message using parens.

The people who have I have talked to–well, listened to–about this rule are passionate about it and convinced that it increases readability and communicates intent. I want to get behind this rule, I really do. it’s a clear, bright-line rule for when to use parentheses or not. It’s the sort of rule that might get included in a book about ruby, for example.

But…

But I still have a problem with this style: when I went full-on no-parens mode, I was forced by the ugliness of my code to refactor it to be simpler and cleaner. When I use this paren style, I can feel that pressure evaporate. I’ve tried this rule for a week, and and I can feel my code quality suffering. I’m not convinced it’s a good rule.

Maybe I just need more engineering discipline. On the other hand, however, I have found that coding styles that require more discipline tend to embarrass me when I don’t step up. I gravitate much more strongly to coding styles that encourage and support me in having more engineering discipline, because they result in me writing better code.

But that brings me back to square one, which is trying to convince everyone to try giving up parentheses all over the place, and I don’t know if I have enough tin foil hats.

So that’s where I’m at. Thoughts?

8 thoughts on “Parentheses in Ruby

  1. Alex Young (@regularfry)

    Interesting thoughts all. The one point that springs to mind right now is that I will always default to using parens on a no-arg private method call. Why? So that it’s impossible for me to accidentally refactor the code later in such a way that the parser trips up and mistakes a method call for a local variable.

    That’s where my thinking is right now: by leaving the parens in, you will *generally* write code that’s more malleable. I like and use the Weirich rule for blocks; I hadn’t come across the application of it to method calls before this week, so I don’t know quite how I feel about it there.

    Reply
    1. dbrady Post author

      That’s interesting–at first I was like WHAAAAAT?!? about your private method technique, but I like that you’ve reasoned through why you do it. After giving it some thought, I think you are protecting yourself from something that I am not afraid of. What I don’t know is if I’m unafraid because I find it easy to detect and deal with, or if my other habits and techniques make it a very rare occurrence. Probably the latter; I don’t write private methods very often to begin with.

      However, when I do write them–and this is kind of a cool thing–I like to leave off the parens for exactly the same reason you put them on: because I place a positive value on being able to implicitly refactor a local variable into a method call. I find myself doing this far more than I catch myself debugging accidental versions of the same refactoring. Very interesting that you place a negative value on the same thing I place a positive value on… Makes me say “People sure are funny sometimes.” I love it when weird/cool stuff like this happens. 🙂

      A couple of people have mentioned malleability to me today, but I’m not sure that word means what I think it means, so there’s another great avenue for more discussion.

      Thanks!

      Reply
  2. Mike Moore (@blowmage)

    I have been using the Seattle.rb’s version of the “Seattle.rb style” for the past couple years and I can say with confidence that it has made me love ruby even more. I agree with all the points that you make here, and I’ve been beaten up by paren lovers regularly for it. (Most of the complaining comes from not using parens on method definitions.)

    Now I tend to look at parens as a detector for code smells. If the complaint is that the method definition is hard to read when you have 4 or 5 method arguments, then the problem isn’t the lack or parens, it’s having too many arguments. And on the other side, if ruby complains because of ambiguity due to lack of parens, then the problem isn’t the lack of parens, its doing too much on that line.

    I run into both of those situations, and more, daily. Confusion or warnings due to “missing” parens forces me to take a breath and reevaluate what I’m trying to accomplish. Like tests, it gives me rapid feedback on the design of my code. The result is that my code maintains a much more consistent level of abstraction, and I don’t violate SRP as much as I used to. It’s not a question of preference, it’s about helping me be a better programmer.

    Reply
      1. dbrady Post author

        I generally like the Weirich Rule. My extended form of it is that the block inside the braces should be short, preferably a single expression. It really bothers me to see a 5-line do…end block that has a chained method call on it, like

        foo = dingbats.map do |dingbat|
          ...
          ...
          ...
        end.reduce :<<
        

        Yuck.

      2. Mike Moore (@blowmage)

        Dave, you shouldn’t defend a rule with “bad” code. 🙂 You can easily rewrite that code example by giving the logic in your block a good name:

        def format_dingbat dingbat
          ...
          ...
          ...
        end
        
        foo = dingbats.map { |d| format_dingbat d }.reduce :<<

        Or, even better:

        def format_dingbat dingbat
          ...
          ...
          ...
        end
        
        def formatted_dingbats dingbats
          dingbats.map { |d| format_dingbat d }.reduce :<<
        end
        
        foo = formatted_dingbats dingbats

        IMO the problem with your code example isn’t the do/end block, it’s an inconsistent level of abstraction. ♥♥♥

  3. Dan Dorman

    “Matz chose to sacrifice first-class functions just so he could make parentheses optional.” Seriously? Man, I love Matz.

    I really, really enjoyed this post. I appreciate the thought you’ve put into it. While I feel like I have an intuitive grasp of the paren situation, I’ve never stopped to figured out WHY something felt good or bad. The reasoning you’ve outlined above sheds new light on this (for me), and I think it will make me much more thoughtful about future code.

    Reply
  4. Ludovic de Luna

    I have a lot of habits, but specific for Ruby (apply other language style programming should be a mistake).

    So, to represent an flow continuous action with a block proc (or yield), I prefer this :

        object.method.method.method { |x| single_line block }
    

    OR

        object.method.method.method do |x|
            multiple_line block
        end
    

    But never :

        object.method.method.method do |x|
            multiple_line block
        end.method.method
    

    In this case, I prefer :

        object.method.method.method { |x|
            multiple_line block OR mono_line block
        }.method.method
    

    Really clear. The flow continues, even if your block is mono line.

    For parenthesis, this is simple : Method that nest other parameters use (). But not the overall statement. From your example :

        puts array.delete(hash.fetch(:foo))
    

    Really not great. In the same case, I prefer :

        puts array.delete(hash.fetch :foo )
    

    More balanced…

    In other case, method definition use always parenthesis. But call to this methods use parenthesis when it’s required : You pass a nested things like object.method parameter(s).

    That was my 2 cents from my experience.

    Reply

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s