What I Do29 Aug 2015
I have a very narrow set of skills, which can be summarized as “delving into a language and helping others understand and (sometimes) solve problems involving that language.” That’s too simple, however – because I ultimately seek “the best” language, for my own personal definition of “best.”
I also leave languages behind. While I once knew all the ins and outs of C++, for example, I stopped studying that language after C++98, searching for a language that gave me more.
I have always sought the most powerful languages. For me, the most important aspect of “power” is programmer productivity, and this is predominantly determined by simplicity and clarity. So I seek languages that emphasize simplicity and clarity above all. I am very aware of the cognitive overhead of language features, and the limitations of the human mind in managing complexity. The more of the mind that is used on arbitrary complexity, the less is available to solve the problems at hand. Thus, I seek languages that don’t force the programmer to jump through arbitrary complexity hoops in order to compensate for language decisions that were made for reasons other than “simplest for the programmer.” I’ve found that once I discover the compromises and what they cost – and especially when they cost more than the language benefits, in terms of programmer time and effort – I start losing interest in that language.
Over time, my perception of “the most powerful language” has been a moving and evolving target. When I long ago began working with C++, it seemed like the best combination of features supporting program abstraction while at the same time enabling C programmers to migrate from C (and reuse their C code in the process). C++’s constraint of “backwards compatibility with C” produced both that evolution path and the added complications that slow programmers down. Although I was heavily immersed in C++ during its early years – depending on how you count, I wrote three or four books on the topic and I was on the C++ Standards Committee from its inception and for the first eight years (for selfish reasons: I found it the best way to learn the intricacies of the language) – I did not study the language after the C++98 standard.
Languages like D and Go have emerged to attempt to solve the C++ complexity problem while maintaining the C++ speed of direct hardware connection. I have great admiration for Go, but I personally find the lack of classes to be too limiting. Classes are certainly not the answer to all problems, but there are times when they are an excellent solution and not having them feels overconstrained.
Java brought virtual machines and garbage collection into the mainstream, but in its headlong rush to dominate the programming world it made irrevocable decisions that have slowly but inexorably squeezed it out of most of the very areas it sought to dominate (for example: Applets, J2EE, Jini, and user-interface programming).
I’ve spent a couple of years immersed in Scala (longer in calendar time, but safe to say two years of full immersion) and feel like I have only a surface understanding of that language. I like to think I understand what’s in Atomic Scala, but even then I am unsurprised when someone points out some feature that turns out to have far greater complexity than I thought.
I’ve come to view Scala as a landscape of cliffs – you can start feeling pretty comfortable with the language and think that you have a reasonable grasp of it, then suddenly fall off a cliff that makes you realize that no, you still don’t get it. Scala has been an amazing experiment and a terrifically valuable learning experience for me, but I feel like I put a lot of effort in writing Atomic Scala so as to present the language in a simple fashion while hiding those cliffs (and I don’t feel too comfortable with that realization). The language left me feeling like I would never be able to completely understand it. On top of that, the reliance on the JVM (and its design decisions) adds some of the same needless complexity that encumbers Java.
One of the issues I had with Scala is the constant feeling of being unable to detect whether I just wasn’t “getting” a particular aspect, or if the language was too complex. This is a hard thing to know until you have a deep understanding of a language. A large portion of the Scala community seems quick to declare that yes, you don’t get it. But if you’re considering using Scala, you owe it to yourself to first watch this presentation by Paul Phillips (the video doesn’t show the slides so you need to get them here). Paul makes a compelling argument that he has written more Scala code than anyone (he worked on the compiler for years), and he also shows how broken the language is – while at the same time stating that it’s possible to be very effective with Scala. He also declares that the language is, in fact, too complex. This doesn’t mean you can’t or shouldn’t use Scala, or that you can’t have a perfectly good experience by staying within a self-imposed box of simplicity.
So I investigate these languages and, when I begin to find them too limiting for various reasons, move on. A language in which I might once have been considered an expert, I leave behind and in so doing lose that expertise. But ultimately I can’t tolerate the thought of programmers wasting time understanding and compensating for decisions that were made for efficiency or expedience or anything other than programmer productivity.
What you consider productive may differ from my definition. For me, it’s “How easy is it for the programmer to think about this problem using the programming language? Where does the language get in the way of expressing the solution in the simplest form?”
The one language that has kept calling me during all of my explorations is Python. To me, the philosophy of Python can be summed up like this: “Nothing is more important than simplicity and clarity.” (In 2009, I created the Pycon (Python Conference) T-shirt which said “Elegance Begets Simplicity”). While Python will do its best to be fast and to solve the numerous technical problems faced by programming language designers, it will never do so by compromising simplicity and clarity. Sometimes this means a feature will not appear in the language for a long time, while the community absorbs and understands the problem it’s meant to solve, but when that feature does appear it’s almost always the clearest and simplest way to think about that problem (and if it isn’t, eventually it gets fixed). For example, the new coroutine support in Python 3.5 took over a decade to evolve.
Whenever I’ve had to solve a problem, I’ve always reached for Python because it’s the fastest way to get to a solution. When I consider using one of the other languages I’ve studied, the overhead of development is so much greater that it just doesn’t make sense. And, during my study of organizations I’ve seen how important culture is, and the Python community has done a masterful job of creating a culture and a community, like nothing I’ve seen for any other programming language.
From these realizations, after my current project (collecting all my Java writings into an eBook), my plan is to write “Atomic Python” and to go dwell in the world of Python; it has become clear that this is the right place for me. I still seek an optimal solution for the user-interface problem, and right now the most likely candidate is Elm, precisely because its philosophy follows that of Python (However, right now I don’t understand Elm well enough to have written anything in it, but I do know of one UI designer who uses it exclusively).
My mission is to try to find the most productive language or combination of languages, using my own definition of “most productive,” which is a rather pure pursuit and does not take into account the various corporate contexts and constraints under which many folks must work.