Why McConnell was wrong: Idiomatic programming
This is a topic that’s been on my mind since I read Code Complete, Second Edition. I think in general, Steve McConnell is right on the mark in Code Complete, but there’s one point which I really disagree with him on: Programming into your language. It first comes up in section 4.3, and is reprised in section 34.4. He repeats the point throughout the book (if it had just been one instance I would have forgotten about it, but he hammers away at every opportunity).
So, what does McConnell mean by “programming into your language”? Referencing David Gries, he says:
Programmers who program “in” a language limit their thoughts to constructs that the language directly supports. … Programmers who program “into” a language first decide what thoughts they want to express, and then determine how to express those thoughts using the tools provided by their specific language.
He later says that you should not
limit your programming thinking only to the concepts that are supported automatically by your language.
I think this is dangerous thinking. To me, it’s very similar to the concept that you can write FORTRAN in any language. Just because you can write code in one language like you would in another language doesn’t mean that you should. I think it leads to the narrow-minded view of programming that there is one “right” way to do everything.
The example he gives is cleaning up Visual Basic code by enforcing a separation between presentation and business logic which the environment actively discourages. In this case, I think it’s great to try to enforce some order, if you know that your language is encouraging poor practices. But most languages (worth using) don’t generally encourage poor practices. There’s a difference between correcting your language where it has done something wrong, and shaping it because it does things differently. To illustrate this distinction, here’s a JavaScript example:
Something JavaScript got wrong: implied globals. If you assign to a variable without declaring it with
var
, it gets global scope. The fix: always declare variables withvar
before use. Use JSLint to enforce this.Something JavaScript did differently to most other languages: prototypal inheritance. The fix: don’t fix it; it ain’t broke. Learn how to think prototypally and do it the JavaScript way.
Both of the above solutions are examples of idiomatic programming in JavaScript. There’s no need to work out in every language what it got right and what it got wrong - just follow the idioms.
Idiomatic programming
So, what is an idiom? This concise definition is from Christian Lescuyer on Stack Overflow:
A programming idiom is the usual way to code a task in a specific language.
In English you say “I am hungry”. You can say the equivalent in French (je suis affamé), but people just don’t. It is a grammatically correct statement that is never used. It is not a French idiom. Instead in French you say “j’ai faim”, which means “I have hunger”, which in English is a grammatically correct phrase that nobody uses. “I have hunger” is not an English idiom. Writing English or French is not only a question of producing grammatically correct phrases, but also to apply correct usage and to use the correct idioms.
This is used to illustrate the point that although there are many ways to write “grammatically correct” C code, only some of them are idiomatic. Writing un-idiomatic C code is the equivalent of saying “I have hunger” in English.
Why use idioms?
Idioms are like the distilled wisdom that has accumulated in the community around every language. Different languages have varying degrees of accepted idiomatic usage. For example, it is generally considered poor form in C++ coding to use every available language feature, but which features to use are not agreed upon. In Python, there is a strong emphasis on writing “Pythonic” code. The Ruby community seems to believe strongly in “Best Practices”.
There is a reason why these idioms exist, and are so widespread - they make it easier to code in the language, and they make it easier for others to read your code. After all, as Martin Fowler wisely said, “any fool can write code that a computer can understand”. The one thing that readers of your code will have in common is knowledge of the idioms in the language it is written in (hopefully). Using the language’s idioms makes it easier for the readers to read it. Being familiar with the idioms makes it easier for you to read code written by others.
JavaScript is currently maturing as a “serious” language, and so is currently lacking in widely accepted idioms. Douglas Crockford makes a strong case for using prototypal inheritance in JavaScript; after all, this is the built-in inheritance mechanism. Others have tried to make JavaScript follow a class-based inheritance pattern. To me, this is an example of “programming into” the language, by making it work in the way one might expect, but not in the way it was designed. I hope the prototypal pattern will win out, but that remains to be seen.
Go with the flow
The important thing is to go with the flow. If a language and its community push you towards a particular practice, go with that. If the language pushes towards something but the community pushes towards something else, it’s likely that the community has spotted a deficiency in the language and is compensating for it.
Learn the idioms, and apply them. Don’t be afraid to try out idioms from other languages, but also accept that there’s likely a reason why they’re not idioms in your current language. Sometimes the only reason is because “that’s just not how it’s done round here”, but that’s a valid reason. Older versions of Rails used for post in @posts
in generated views to iterate over lists of model objects. The newer versions use the more idiomatic @posts.each do |post|
. Rubyists like blocks, and that’s enough of a reason to use the latter version.
So was McConnell wrong?
I think McConnell was wrong to make the blanket statement “program into your language, not in it”. I think what he really meant was to protect yourself from your language when it forces you to do bad things, but it doesn’t come across like this.
Further reading
Steve McConnell: Code Complete, Second Edition: Despite being wrong on two pages, the rest of this book is an excellent distillation of decades of computer science research and industry best practices.
Jon Skeet: Programming “in” a language vs programming “into” a language: Jon Skeet of Stack Overflow fame has already written on this subject - I came across his post while researching mine. I almost didn’t write this post after finding Jon’s, but I decided that although we agreed, we had very different perspectives.
Keyvan Nayyeri: Program into Your Language, Not in It: Nayyeri agrees with everything that McConnell says on the subject - I’ve included his post here for balance :)
Programming idioms: A good discussion on idioms, from a C perspective.