Victoria Lacroix

The Flexibility of Good Tooling

2026-08-20

I have a question for you. Consider it carefully.

What is the best wrench? If you're English—what is the best spanner?

One could argue that an adjustable wrench is pretty handy to have. Being adjustable makes the tool suitable for a wide variety of applications, but the moving part is also a weakness that once worn down leads the wrench to becoming unusable. Combination wrenches do not suffer nearly as much wear and tear, but one must also own the right ones for the right situations. Neither type is suitable for plumbing, where the aptly-named pipe wrench reigns supreme. Do vise grips count as wrenches? A ratcheting wrench can allow the user to work much more quickly, but suffers the same wear-and-tear as the adjustable wrench due to its moving parts.

You see, the subjectivity of the answer reveals the seeming pointlessness of the question at hand. There can be no single "best" wrench because contexts change the unspoken parameters of the problem space, and thus the warranted solution is in constant flux.

With this in mind, I ask:

What is the best programming language?

It's a question that has been posed for decades, since the invention of programming languages. Each language was built to solve a certain class of problems particularly well. COBOL was built for business databases. C was written to make it easier to write programs for the PDP-11 on which UNIX was made to run. Javascript was developed to torture web developers. Assembly languages weren't even really made so much as derived from how computer processors worked. Some of these languages have fallen by the wayside, no longer as popular or widely-used as they once were. Others still go on strong.

Does that mean a language like Assembly could never have been considered "best" if it is woefully insufficient today? Hardly. Some of the best video games ever were programmed in assembly language; Pokémon Crystal and Roller Coaster Tycoon 2 would not have had the cultural impact they did if they'd be written in other languages. Both games would've been smaller, slower, and probably much less interesting because Assembly was a necessity to squeeze as much performance out of the platform as possible.

The other wrinkle in this framing is that for both games, the developers were very familiar with the platform and knew exactly how to use assembly to its fullest in those contexts. They had mastered the right tool at the right time for what they were building, but that mastery could not fully transfer. Not knowing much about COBOL, I suspect the same was true. Knowledge of COBOL could not transfer to other problem spaces because it was too specific. As suggested by the fact that they continue to be used, neither C nor Javascript have this problem. These languages can be used in a variety of ways, for many kinds of software applications.

So that settles it, right? The best tool is the one that is flexible.

I think there is more to this.

A programming language is never simply a programming language, otherwise it'd be possible to 100% faithfully transpile from any language to any other. That this is not possible suggests there is something more.

Every programming language implicitly comes with a platform. This can be a combination of runtime libraries, dependency management and packaging, and core language features. Some languages have their own object-oriented programming systems, where others require the use of external systems. Certain languages allow functions to be defined within any scope, while others only allow functions to be defined in a global scope. None of these differences are enough to make less featureful languages obsolete on their own; It is still possible to write the same programs and solve the same problems, except the solutions would be a little different. If the absence of object-oriented programming doesn't deter the programmer from solving a certain kind of problem, then its absence from the language doesn't matter. The opposite is not true, however.

The inclusion of a programming feature which doesn't meaningfully change the kinds of problems a programmer can solve would seem to be an innocuous difference, but it isn't. Viewing a programming language not as a mere tool but as an entire platform on which to build solutions, every new feature is another tool in the toolbox to be learned and mastered. Every new feature is another choice a programmer must make on how to solve a given problem, and another obstacle in the way of the mastery.

Mastery of a craft leads to better work. Work of a higher quality. Faster work. Better solutions to problems. The best vase is not the one that is carefully crafted for months on end—it's the one cobbled together in a matter of hours by someone who has made so many that they regularly craft masterpieces without ever setting out to do so.

The distinction in platforms offered by different programming languages has implications on the act of mastery. A programming environment with as much historical baggage as C++ could not possibly be mastered by anyone. A simpler one can, and unlike those adjustable or ratcheting wrenches the nature of wear and tear is very different in the land of software development.

Flexible programming languages don't fall apart from overuse. The closest equivalent I can think of would be frequent updates introducing new features and deprecating old ones—i.e.: how often a programer needs to adjust to a changed programming environment. Put another way, certain programming languages will occasionally need to be re-mastered by their users.

Putting all of these thoughts together, I think I finally understand why Lua works so well for me. It is a tiny language with only a few hundred built-in functions. Its features—particularly its core arbitrary data type, the table—are maximally flexible while still being robust enough to solve real problems. Its oddities are a result of very careful deliberation from its designers. The language itself receives a major feature update every 5 or so years, though the rate of change is gradually slowing. If a new feature supercedes an old one, the old one is removed. Lua prioritizes leanness over backward compatibility. This is great for aspiring Lua users as the language remains small enough to learn and eventually master, and the slow pace of updates to the language make it relatively easy for masters to carry their knowledge over from prior versions.

Because Lua also works excellently with C code, writing extensions which interact with the underlying computer system is not terribly difficult. That is to say that not only is Lua's C API easy to master, the benefits of mastering the language can carry over to a wide variety of problem spaces. For someone like me, this makes Lua into the ultimate flexible programming language—I learned it easily, and as a benefit it has become something I can consider throwing at any problem I encounter.

Of course, most other programming languages have APIs for interacting with C. After all, C is the lingua franca of computing. Operating systems and core system libraries are written in it. So, merely having a C API does not set Lua apart—but being relatively easy to master certainly does.

One of the other benefits of Lua's small size is that it is relatively feasible for a small team or even an individual to implement their own version of the language. In doing so, they may choose to optimize their runtime for a different outcome than the reference implementation. This is exactly what motivated LuaJIT, a Lua implementation optimized for speed. It uses just-in-time (hence the "JIT") recompilation to achieve speeds unmatched by the upstream version of Lua. Additionally, LuaJIT also includes an alternate C API that allows the user to interact with C libraries while only ever writing Lua. Sticking with LuaJIT, the Lua master will seldom need to touch anything else.

Programming languages which are more complicated can of course still be mastered by their users. Javascript is an example which comes to mind. Because it is the language of the web browser, anyone who wants to write an interactive web page or web application will need to know Javascript. Someone especially experienced in doing so will learn its quirks—its ins and outs—and like me will seek out other ways to apply their mastery if possible. Node (or, NodeJS) is exactly that. It is a Javascript runtime for writing software outside of the web browser. Because this included server software, building website backends using Node allowed web developers not only to use the same language at all levels of a site but also to even share some code between these levels. The benefits of mastery make themselves clear, even if the path to it is different and in some ways more difficult.

Flexibility is not only a property of programming languages, nor is it specifically a property of good programming tools. Flexibility of a platform can in some ways be viewed as a phenomenon which emerges from mastery. Mastery can elevate a language beyond the niche for which it was optimized into. The master of a given programming environment will write high-quality code quickly, and be able to solve a variety of problems. The language in question is not especially relevant, either.

The best tool is the one that is flexible enough to solve a large class of problems, but the great tool is the one that gets you to that point more quickly.

Reply to this post