The One Best Programming Language
I’ve recently listened to an interview with John Carmack, one of his generation’s most celebrated programmers. One thing he mentioned in passing is his belief that programmers should focus primarily on one single programming language. This surprised me a bit. Not because I think it’s wrong - quite the contrary, I know this from my own experience to be very sensible advice. But because I realised that despite it being intuitively correct to so many programmers, this opinion would be considered controversial in many contemporary circles.
I am, I guess, what you’d call a veteran programmer. I’m getting older, I’ve been programming for almost all of my life, and in a professional capacity for all of my grown-up years. I have, at times, considered myself a programming language enthusiast and experienced first-hand many of the developments in programming language evolution. Looking back, it’s been an exciting history, and one that almost inevitably had to lead to the (wrong) conclusion that it’s a good idea to be promiscuous with the choice of a programming language. And as exciting as history is, so is the current state boring. And I mean “boring” in the most positive sense of the word.
As I am now myself (somewhat unexpectedly) at a crossroads, ready to re-evaluate my own choice of primary programming language, I thought it would be useful to review how we got to where we are, what lessons can be learned, and finally, what programming language is in fact the best one to standardise on.
Prehistory (1950s ~ 1980s)
(By prehistory I mean, of course, everything that happened before I was around to witness it. No disrespect to those who came before and got things going).
Computer programming (beyond the instructions native to processors) evolved slowly in tandem with the evolution of computing hardware and of computer science as a discipline. For the first few decades, programming languages as an object of study were of interest primarily in academia, and even there to a small group of researchers. Most programmers used whatever was available, and that depended mostly on the domain. If you did “business” programming, you used COBOL. Fortran dominated scientific programming. A few other languages emerged, and were usually tied to a specific domain, strand of research or hardware. For most programmers it made perfect sense to focus on that one single language, sometimes for their entire programming career or for a long stretch. And while there were people interested in the design of programming languages, the field was yet to mature and even as some interesting results started to emerge, there was not yet a good understanding of how to design a good programming language.
Professionalization (1980s ~ 1990s)
With increased deployment of computing hardware and a growing diversity of uses, the number of programming languages increased somewhat, and the choice of programming language became a relevant question. What developed was akin to a class system. A programmer’s choice of language could be predicted by what kind of programmer they are, and especially what level of professionalism they aspire to. Hobbyist programmers of the ever more popular personal computer used BASIC. A ridiculous, primitive language, but one that was widely available and became the entry point for a generation of new programmers (myself included). Pascal introduced structured programming to the masses and has had real impact (it had a thriving community with Turbo-Pascal and then Delphi, but eventually died out). C emerged as the language of system programming thanks to its origin with UNIX. C++ took the power of C and adopted object-oriented programming from Smalltalk (a lovely language that never really gained momentum) and became the language of professional application and service developers. Eventually Visual Basic (which has basically nothing to do with the original BASIC) popularized “visual programming”, satisfying demand for application development (which grew rapidly with the availability of Windows) and becoming the tool of choice for “citizen developers” - developers who identify as domain experts doing programming on the side, rather than the “professional” programming of C and C++.
Importantly, programming language design was still not that well understood, with the result that many of the most popular programming languages were in many ways suboptimal. C is simple and powerful, but difficult to program well - there’s so much that can go wrong. C++ had good intentions but ended up being monstrous and unpleasant to use. Visual Basic was fun and easy, but a joke of a language, inelegant and inefficient in ways that it really didn’t have to be, given the technology of the time. Smalltalk and LISP, both interesting and elegant languages with quite the pedigree, lost the race due to tying themselves to specialised hardware and expensive tooling.
Sophistication (1990s ~ 2000s)
Many other languages appeared in this period, but an especially important development is Java. The language itself is hardly exciting, but with it came the JVM, a general runtime environment that would allow you to “Write Once, Run Anywhere”, that is, the language is general and its use not tied to particular hardware, operating system, or target environment. Technically, the early JVM was nothing to write home about, but it ushered an era of increasing sophistication in language runtimes and deployment options.
Proliferation (2000s ~ 2010s)
What started with the JVM soon evolved in an interesting direction. Research on Just in Time (JIT) compilers that originated with Self (a wonderful but doomed successor to Smalltalk) made it to Java via HotSpot, and to the .NET CLR, Microsoft’s answer to Java. .NET took things a step further by designing the CLR (Common Language Runtime) to be a general runtime for multiple language, not just for C#, Microsoft’s Java clone. In hindsight, this was a watershed moment - the first time it was explicit that the world is becoming programming language agnostic. That might not have been the main reason for Microsoft making this choice (they were committed to continue supporting Visual Basic, which was still extremely popular, alongside C#), and owing to Microsoft’s closed licensing during that period the CLR did not become the most popular runtime environment. But as the first decade of the first millennium gained pace programming languages were many, and everywhere.
Another thing that happened is the explosion in the number of programmers. With demand for software growing rapidly, and with increased availability of tooling and knowledge, millions of people around the world were now becoming programmers. Programmers, just like chimpanzees, share more than 99% of their genes with humans. And like humans, they have that tendency to develop strong group identification. Much like normal humans tend to develop strong and irrational identification with a football club or a political party, programmers suddenly became vocal in their advocacy for this programming language or another. And like other hominids, programmers are also individualistic to a fault. Of course, many of them had to choose that new, exciting, programming language, to show how unique and special they are. Functional programming is king - everyone not using it is a loser. Ruby is better than PHP, so much better. Scala will revolutionize data science. Haskell or bust. Clojure or you really don’t know what you’re talking about. The evolution of programming language changed from mostly linear progression, where every new language represents a genuine step change, into a chaotic, Darwinian process.
Hypernormalization (2010s ~ Present Day)
This would have been the time to realize that something crazy and unsustainable is going on. But that’s not what actually happened, not at all. Instead, things have taken an unexpected turn. In the age of “cloud” computing, with many applications and services spanning a large number of distributed nodes across the Internet, the need to decide what programming language to use seemed irrelevant. If programmers are anyway developing many independent components that are operating in tandem, why choose? One component really doesn’t need to know which programming language the other components were written in. And the programmers, well, if they’re so passionate about writing their component in language X, let them have X. Who cares.
And if that was true for components running on different machines, then containers, popularized by the release of Docker, made it easy to manage using the same paradigm even on a single machine, or on a cluster of machines operating cooperatively using orchestration software.
At the same time, it feels like the world of programming has reached a new level of maturity and no longer has a need to chase every new trend and adopt every new language. We’ve grown up.
The Case for One Programming Language
There’s no question that some programming languages are better than others, and that some programming languages are especially useful for particular use cases, in a way that other languages aren’t. Another thing that is clear to anyone who does programming for a while, is that picking up a new language isn’t hard at all. Most programmers can easily learn the basics of a new language in an afternoon and become more-or-less productive after a few days of use. And new programmers can start with any mainstream programming language and transfer their newly acquired programming skill to pretty much any other language easily.
There are, however, two reasons why switching programming languages too often is a bad idea. First, programming in a language is a bit like chess. You can learn the rules quickly, but that doesn’t mean that you can win against an experienced player. You need to learn your gambits, and that takes time and practice. There are best practices, gotchas, optimization techniques, and an entire ecosystem of libraries, tools, and community outposts. Second, programming is easy, but error prone. Even with general programming experience and the best tooling, translating ideas to computer code is not an intuitive act. Whatever intuition a programmer does develop, comes from repeated use and an immediate feedback and correction loop. Every time you switch a language, you’re paying a price in the level of automaticity you can perform. So, if there’s anything I (and millions of other programmers) have learned it is that yes, your choice of programming language matters, but that once you’ve made your choice, you’re better off sticking with it for the long run.
How to Choose a Programming Language
There are a few things to consider when choosing a primary programming language in 2022. The most crucial factor, I think, is how widely applicable the language is. While some domain-specific languages are a must if you need to generate results in a specific domain, the most useful language would be one that is generally applicable. Thankfully, since the days of Java’s “Write Once, Run Anywhere”, runtime and deployment options aren’t really a concern. Neither is cost or licensing restrictions - in 2022 all programming languages, runtimes, and to a considerable extent other tooling, are freely available. If a language isn’t applicable for a particular scenario, it is either because it’s not popular enough for anyone to make the minimal effort required to make it available, or because there is something fundamental that means the language isn’t suitable for the task. Popularity is important - it’s best to work in a language that has a strong community, rich sources of information, large pool of other programmers to collaborate with or hire. Any language that isn’t wildly popular is a poor choice. Suitability for a particular scenario is a bit more difficult. No language works equally well for all scenarios, but a general, primary language, should ideally target many, most, scenarios well enough. Finally, our language of choice should be one that is generally better than most other languages. Even in 2022 there are some lousy programming languages out there that are hard to learn and use and make it easy for a programmer to shoot themselves in the foot.
Given these parameters, I think that the selection is actually quite narrow. Let’s look at the options.
The Best Programming Language
Rust is “C++ that doesn’t hurt”. It has all the power of C / C++, but is much easier to use, and without shooting yourself in the foot. Strong and growing community and ecosystem. Good tooling. Rust is definitely a good bet if you need the kind of power it provides. Rust is quickly becoming available in scenarios where previously only C or C++ were available. And it is establishing itself the lingua franca of WebAssembly, the ultimate “Write Once, Run Anywhere” runtime.
It hurts to write this - I’ve been a Pythonista for over two decades - but in 2022 Python can’t really be considered a general-purpose programming language. One reason is that it is still horribly inefficient, and not suitable for many scenarios where performance matters. Another is that it failed to make it into important user-facing environments like the web browser or the mobile phone. It is still a great language, though, and has occupied an important niche in data engineering / data science / machine learning, so definitely a language to know and love if you do any work in these fields. The way things look like right now, Python will likely live on for a long time to come as the lingua franca of data science, but will probably not gain more ground beyond it.
Go is a great language for “cloud” programming. It is elegant, easy to learn and use, has a great community, ecosystem, and tooling. It is widely used in key products in the cloud-native space, which means that it’s going to be around for a while. Unfortunately, it is not that generally applicable - it can’t be used for much in environments that aren’t, essentially, “internet servers”. Also, because of choices the designers of Go made, it doesn’t play nice in the C / C++ world. Go is lovely, but if you have to make a choice, Rust can do everything Go does, and with time will likely replace it as the main systems programming language.
C# / Java
C / C++
The Lindy effect means C and C++ will continue being very popular and important for decades to come. If you are already an expert you can expect to remain productive and in demand. If you must use them, they are a good investment. If not, Rust is a better choice.
Swift / Kotlin / Dart
LISP (Racket / Clojure)
LISP is special, and even if you don’t use it day-to-day it’s worth learning. Racket is the state-of-the-art, very sophisticated language (or actually, a language construction kit). Clojure is supposedly powerful because it targets the JVM and can use Java libraries. Not sure how much of a selling point that really is.
Haskell / F# / Scala
Functional languages are important. There are scenarios where they are preferable to any other option. Haskell rules. F# is supposedly more generally applicable because it targets the CLR and can use .NET libraries. Scala is not pure but very versatile and targets the JVM.
Julia / R / MATLAB
Julia looks especially promising for doing math. R and MATLAB are applicable in particular scenarios where they are well established. It’s hard to see any of those surviving the dominance of Python in data engineering, though.
If you do the kind of things people do with shell programming, PowerShell is by far the best. It has been available for all operating systems for a while, so there’s really no reason to use any other shell. It is “sort of” a general programming language, but in practice you wouldn’t use it for anything that isn’t system administration.
PHP / Ruby / PERL
These languages had their day, mostly as web “back end” languages (PERL first as a shell+). Regardless of how you feel about these languages, there’s absolutely no reason to touch them today. They’re dead.
Visual Basic / VBA
VB changed the world, but is no longer relevant, either as a general language or as an extension to other programs. Everything that could be done in the distant past with VB can now be done better with other, modern languages.
I love programming languages and will forever be curious about the development of new ones. For the time being, though, I’m betting big on TypeScript as my primary language, with Rust as a second language for situations where I need its power and low-level access. That doesn’t make me special - this is the obvious choice for almost any programmer in 2022. Being special is overrated.