In Robert Frost’s poem, “Mending Wall”, two farmers meet each spring to rebuild the rock wall between their properties. One farmer is the narrator. He notes that the unseen forces of winter and weather always cause some decay (“something there is that doesn’t love a wall”), and he wonders why the wall is necessary. There’s apple orchard on one side, and pine forest on the other–it’s not as if something will be kept in or out. The other farmer answers with the repeated aphorism “good fences make good neighbors.”
photo credit: DragonWoman (Flickr)
This poem could be a treatise for the principle of encapsulation in software. In software as in life:
- Something there is that doesn’t love a wall.
- Good fences make good neighbors.
What doesn’t love a wall?
Subroutines, formal interfaces, data hiding, class hierarchies, the pimpl idiom, and similar mechanisms all create barriers in software between consumers and providers of functionality. These techniques are well known, but we still have codebases littered with protected data members, unnecessary class declarations in headers, goto, and other suboptimal choices.
Why? Continue reading
A while back, I was reading the blog of somebody smart (can’t remember who), and a comment jumped out at me: “If you really want a black belt in computer science, try writing a programming language. The depth and breadth of experience you get when you invent Python or Lisp or Smalltalk or C++ or C#–and implement its ecosystem, not just code a parser for a CS class–gives you a wisdom and education that’s rare and precious.” (I’m paraphrasing here, but that’s the gist of it.)
Sounds good, I thought. I think I’ll give it a shot.
“Confusion of Tongues”, by Gustave Doré. The Tower of Babel resonates beyond moral history. Image credit: Wikimedia Commons.
I began doing research and taking notes. I thought hard about which features I liked and detested in programming languages. I read critiques and tributes to various languages by detractors and fans. I identified pieces of syntactic sugar that I wanted to support. I took a wad of existing code and tried to rewrite it using the language I was drafting. I picked some conventions for filenames. I played with yacc and antlr and experimented with definitions of context-free grammars.
And then I stalled.
It wasn’t good enough.
My new language was nifty. It combined a lot of the best features of my favorite languages: closures, list comprehensions, lambdas, static if, robust type inference, unified function call syntax, with blocks, variadic templates, mixins, nullable primitives, built-in support for design by contract, and more. I actually believed (perhaps naively) that I knew how to implement a good portion of these ideas in a compiler.
But I began to intuit that nifty != great. And the longer and harder I thought about it, the more convinced I became.