Programming With Discretion

In Reviews: The Book of (Weird) Ruby, and Eloquent Ruby, I commented on the coding style Huw Collingbourne uses for Ruby in The Book of Ruby. One statement I made was:

I spent about ten minutes thinking about, and refreshing my memory of, idiomatic styles for other languages, with Google as my guide; I was trying to figure out what language might have been the foundation for this author developing the style he uses. I thought maybe he was doing something like writing C++ in Ruby (as an example -- despite the wide range of styles considered "idiomatic" for C++, none of which I am aware exactly fit the bill). I have not yet come up with a language whose idiomatic style could explain this.

There are two discussions on reddit following Reviews. In one of them, user redditornongrata said:

The camelCaseWithoutLeadingCaps convention in The Book of Ruby is a Javaism. The strange indentation and whitespace is just bizarre.

I responded:

I saw a number of different bits of formatting style in that book's sample code that could be blamed on several different languages' idiomatic styles; the Javaism is one of them. I still have no idea of any single language that could account for all, or even most, of them.

Eventually, Huw Collingbourne commented as well, in one case to offer a link to his response to my Reviews: Programming With Style. He admits right away, at the beginning of Style, that he makes an effort to avoid adopting idiomatic style for the language:

So, when I switch from one programming language to another do I change my coding style to fit the language? The answer is: up to a point. Or, to put it another way: as little as possible.

His explanation involved thinly veiled statements that adherence to idiomatic style for a language when programming in that language is essentially slavish attachment to empty traditions. His choice of terms is not quite so blunt, using phrasing like "fiercely devoted to language-specific idioms". He also states that he dislikes underscores in method names for "aesthetic" reasons.

He goes on to explain that, though apparently people often think he gets his programming style from Java, "That is simply not the case. For some insight into my stylistic preferences, however, you may want to take a look at a series of articles I wrote called Ruby The Smalltalk Way."

I suddenly recalled some similarities between his style and that of some Smalltalk code I have seen following a TechRepublic article of mine, Understanding Ruby Blocks, including the camelCaseWithoutLeadingCaps style of labeling. I have, of course, seen more Smalltalk code than that -- but not recently, so it was not the first thing that came to mind.

Even so, Smalltalk does not explain everything about Huw Collingbourne's style. For instance, I have never seen any Smalltalk code formatted quite the way he did at times. Compare this Ruby code from his book:

["hello","good day","how do you do"].each{ |s| caps( s ){ |x| x.capitalize! puts( x ) } }

. . . with this Smalltalk code from a discussion comment at TR by Mark Miller:

foo := #(1 2 3 4 5 6 7 8 9 10). "1-based array" vals := #(0 1) asOrderedCollection. foo do: [:n | Transcript show: n asString, ': ', (vals at: n ifAbsentPut: [(vals at: n - 1) + (vals at: n - 2)]) asString; cr]

Note the way Mark Miller did not for some reason orphan the block argument on its own line, did not place one expression or statement on the same line as a block argument and opening delimiter while placing others on their own lines, and tended to line up indentations with placement of associated tokens on preceding lines. The style in Mark Miller's code sample tends to match the idiomatic style of Smalltalk that I have seen in the past fairly well, in addition to matching some conventions that are typically observed across different languages. It is reasonably clear and readable, tailored to the linguistic context of Smalltalk syntax, and maintains conceptual clarity by accounting well for the semantic elements of the language.

Though Smalltalk clearly does not account for all of Huw Collingbourne's quirks in Ruby programming style (one might say it does not account consistently for most of them), I can see that Smalltalk might well have had some influence on his style. The fact he writes a lot of C# might account for some parts of it as well, such as the choice of four-space indents. The weird inconsistencies, however, still seem inexplicable to me.

For those of you who are not very familiar with Ruby code, the above Ruby sample would more idiomatically be formatted thusly:

["hello", "good day", "how do you do"].each do |s| caps(s) do |x| x.capitalize! puts x end end

. . . though most Rubyists would probably rewrite parts of it as well. A quick rewrite to suit my preferences and Ruby idioms might look like this:

['hello', 'good day', 'how do you do'].each do |s| caps(s) {|x| puts x.capitalize } end

We will just ignore for now that, in The Book of Ruby, the definition of the caps method is completely useless and makes it a redundant piece of code that adds nothing but complexity to the task. The implementation of caps was used as an example of how to implement a method that takes a block as an argument, and not as an example of good software design (I hope).

In the end, I do not buy into his argument that his personal biases trump the stylistic idioms adopted by the language's community, for reasons I will touch on a bit more in a moment. Before we get there, though, I think it worth mentioning that even if I did buy his argument, I would certainly not buy his notion of the best-ever code formatting style to try to cram into the context of every language I use. I shudder at the thought of how Scheme would look using his preferred style.

On the subject of why I do not buy his argument, let us consider his objections to employing the idioms of the language as jumping-off points for arguments in favor of Ruby's idiomatic style when coding in Ruby, some of which come from Style and some from the introduction to The Book of Ruby:

He apparently objects to "fierce devotion", as indicated in the statement "I came across this (largely negative) review of my Ruby programming book recently, which reminded me of just how fiercely devoted to language-specific idioms some programmers are. The truth of the matter is, I am not." Whether adopting the idioms of a particular language is any form of "devotion" at all or not, this argument in no way addresses the benefits or detriments of employing such idioms. Even so, I for one have no blind devotion to empty conventions. I use the style that works -- to make collaboration with other programmers smoother and more efficient, to keep the look of my code in a given language consistent as an aid to rapid recognition, and to highlight by relative positioning important aspects of the code corresponding to key semantic relationships within the code.

He goes on to complain about differences in conventions for indentation in different languages, saying "I don't make a habit of setting different tab-settings when I switch from one language to another (4 spaces per tab in C#, say, but 2 in Ruby) . . .". Evidently, he has not heard of IDEs and editors that can recognize the language you are using, then automate selection of indentation standards according to language. Vim can do it; I'm pretty sure Visual Studio can as well, and I think that is what he is using.

He continues, with ". . . nor do I change my naming conventions for methods and variables any more than is absolutely required by the syntax of the language." There are certainly some things that, for the most part, should not be changed in labeling conventions from one language to the next -- descriptively encompassing the purpose of a variable or method, for instance. On the other hand, where the syntax of one language differs from another, different types of syntactic clutter arise that might distract the reader if naming conventions are not selected to clarify meaning.

He makes a curious claim, that "Some Ruby programmers have very fixed-or even obsessive-views on what constitutes a 'Ruby style' of programming. Some, for example, are passionately wedded to the idea that method_names_use_underscores while variableNamesDoNot." Of course, actual idiomatic Ruby style uses snake_case for both methods and variables. It seems odd that he would make a mistake like that in his complaints about Ruby idioms unless he simply never took the time to understand them before rejecting them.

He takes a surprisingly provincial view of stylistic idioms. "As far as I am concerned, the way in which you choose to write the names of identifiers in Ruby is of no interest to anyone but you or your programming colleagues." This is fine if you assume you will never have to deal with code outside of an insular little team of developers. On the other hand, taking it upon yourself to write a book about the language and distribute it widely -- a book that flies in the face of the language's idiomatic style -- is the polar opposite of dealing only within your own team of developers. The strong cultural involvement in open source development for the Ruby community places a necessary premium on consistent code style and maximizing compatibility with that style to the greatest extent reasonble. Even small commercial teams still need to be able to learn from outsiders, the foremost experts in the language and the best teachers in its community, and having to translate concepts between wildly disparate styles that are mutually nigh-incomprehensible makes that quite difficult at times.

He dismisses the notion that naming conventions have any value, saying that in his view "good programming style has nothing to do with naming conventions and everything to do with good code structure and clarity." Of course, given that policy, one must wonder why he does not just name his variables a , b , c , and eventually aa , ab , and so on. It is a self-defeating argument.

He sure does like parentheses, though. "Parentheses clarify code and avoid ambiguity that, in a highly dynamic language such as Ruby, can mean the difference between a program that works as you expect and one that is full of surprises (also known as bugs)." Of course, a rule so simple is bound to run afoul of exceptions. In fact, much of the beauty and clarity of Ruby code is tied to the fact that it uses special character punctuation much more sparingly than some other languages. The syntax of the language seems to have been especially well tuned to improve clarity with the reduction of such punctuation in cases where grouping is obvious. By contrast, close proximity of multiple layers of nested delimiters such as parentheses, brackets, and braces can make it difficult to recognize the current level of nesting. Delimiter matching functionality in your editor can help for very localized, precise efforts to untangle parenthetical nesting, but that provides very little help for quickly taking in code within the context of sorting out larger scale program flow. This is one reason why, in Ruby, it is common to leave off parentheses for method calls with relatively few arguments.

Ultimately, I do not begrudge anyone the right or desire to do his or her own thing in the privacy of his or her editor of choice. I believe that programmers' lives can often be made easier by adopting good coding style idioms, but if they for some reason find those idioms limiting, let them do what they wish when it affects only their own circumstances. A problem arises when their choices affect others, however.

First, it is in your own best interest to employ a coding style calculated to maximize the comfort of readers and the clarity and rapid comprehension of the code for readers when you wish to get any kind of input from them. That input might involve code contributions to your open source project or help from a mailing list, for instance.

Second, it is in the best interests of any goals you may have for reuse of your code to employ such a coding style, because given a choice between two codebases -- one of which they find easily readable and another of which uses inconsistent, alien stylistic choices -- the would-be user of your code will generally choose the codebase he or she finds most readily comprehensible.

Third, it is in the best interests of whoever ends up using the software in any case where anyone else will have access to your code, and -- where those users are your customers -- it is again in your own best intersts to use common, effective idioms. That is because readability is an important component of maintainability, and if other programmers are likely to have to maintain your code it needs to be readable to them.

Finally, writing a book intended to be used to introduce new Rubyists to the language should consider the maximum value such a book can provide, and make stylistic choices consistently and with the good of the reader in mind. If you must, make a case for particular deviations from idiomatic style in a limited part of the text; if the deviations are not too great, you can even use them, so long as you make it clear how and why you deviate from the norm. Overall, however, it is for the best to adhere to idiomatic style in any case where an alternate style is not the point of the book. To do otherwise is to do your readers the disservice of indoctrinating them in stylistic conventions that will set them at odds with the rest of the language's community.

. . . and that is really my biggest problem with the code style in The Book of Ruby. I may disagree with Huw Collingbourne's choice of coding style, but do not much care if he uses it for his own private purposes. I just care that he replaces idiomatic style in a book designed to impress good programming practice on new students of the Ruby language. Even that was not the reason I objected to the coding style in my review, though: ultimately, the reason I rated the coding style poorly in the context of that book is that it becomes less readable for me, thus dissuading me from buying it.

I was glad someone else mentioned the un-idiomatic style of the book before I bought it, increasing the likelihood I would give it a critical look for such problems. I figured someone else might benefit from my experience as well.