-
Book Overview & Buying
-
Table Of Contents
Building Programming Language Interpreters
By :
I suppose it is tempting, if the only tool you have is a hammer, to treat everything as if it were a nail.
—Abraham Maslow, 1966, The Psychology of Science
We tend to underestimate how the programming languages we use define the way we write code and the way we handle the problems that are presented to us as software developers. The shape of our solutions is influenced by the tools we have when we’re working on them.
The environments and ecosystems of the programming languages we use shape us as developers. We can sometimes recognize the accent a developer has when they move from one programming language to another, and it takes a certain amount of effort and code review to become familiar with another language and to start talking like a native.
While it’s true that you can solve any computable problem in any Turing-complete language, it’s also true that some problem spaces are better addressed by certain languages, and those tend to become used persistently, even when they’re no longer in fashion.
Fortran is a very good example of that. It has seen an important resurgence in the scientific computing community. It has straightforward semantics, very good support for numerical types, and a lot of efficiency when it comes to computing lots of numerical operations. Those characteristics make it extremely useful in that context, and it doesn’t matter that Fortran is quite literally the oldest programming language still in use.
The ecosystem also defines a lot regarding how problems are solved. C++ has a significant deficiency in how code reuse is managed, particularly across projects. It still has no uniform package management, even though it is probably the language that needs the most amount of support from outside the language for its build to work properly. Header-only libraries in C++ were developers’ response to this deficiency in the ecosystem, and it became a defining aspect of how libraries are made in the language.
Of course, sometimes we also just want to express aesthetic preferences on how we write our code. Programming is not a mathematical exercise; it is much closer to telling a story—a story you tell the computer, of course, but it’s also a story you tell other developers. And it’s easy to underestimate how strongly software developers feel about the choices that are made to solve programming problems.
Those choices are not always made based on empirical evidence—more often than not, they’re derived from the culture that is built around a given community. The Perl community, for instance, was heavily informed by the “There is more than one way to do it” principle of the language itself. This could also be seen in how libraries were designed, with more flexible interfaces and the idea that the goal was to make it easier to solve problems.
This ended up becoming the fuel for a lot of the detraction from Perl, and opposition to it became a driving force in the design of Python, where “There should be one—and preferably only one—obvious way to do it.”
You may have read the previous paragraphs thinking that I would present you with a definitive way to talk about the most important aspects of programming language design and give you the answer to the question: “What is the best and worst programming language?” But I’m going to go in quite the opposite direction.
Instead of trying to find the one ultimate language, our goal should be to use the programming language that best fits the specific problem we’re trying to solve. Sometimes, we may have strong opinions regarding that programming language, but if it allows us to solve the problem more easily (maybe there’s a library in that ecosystem that fits our problem), then we should prioritize solving the problem, independent of our opinions about that particular programming language.
Sometimes, disruption comes from unexpected places, and a language that takes a different approach will allow developers to create better solutions to existing problems. That can create a turning point and attract a lot of people to bootstrap an entirely new community. We’ve seen how fast Rust is gaining popularity, and how its memory management model changes the way people solve problems in that language.
Other times, disruptions occur without us having to replace any existing language. Focusing on niche use cases can create entirely new ways of solving problems. In the next section, we will focus on scenarios like that.