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:
(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 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?