The love triangle of programming languages

Programmers love to hate on programming languages. It feels great to pitchfork PHP, ruin Ruby or pick on Python. 1 Here’s a great resource to get you started. But also, some programmers love to hate programmers who hate on programming languages. Phrases like “It’s not the tools that matter”, “Great craftsmen can make great stuff with any tool” quickly arise and stifle the discussion about the pros and cons of any language.

Personally, I think discussing the motivations behind programming language design is very important to help us shape the environment for the developers of tomorrow. I have developed a little scheme for myself to categorize the strengths and weaknesses of programming languages, and I find it quite useful when debating (usually with myself, though.)

In the “Love Triangle of Programming Languages”, there are three parties that hold stakes when it comes to the design of a language. First, there’s the user. They want to build stuff, obviously. Doing anything should be easy, and intuitive. Then there’s the machine. Well, yeah, after all, somebody has to do the dirty work. Instructions should be clear, simple and unambiguous. Finally, there’s the problem. This is where it gets a bit hairy, because problems don’t usually have needs and opinions. What I mean, however, is the concept that should be implemented, be it an algorithm or something more abstract. Problems, erm, want to be represented in a manner that allows easy destructuring of complex processes.

These opposing positions can be represented by a triangle.

User Problem Machine

A (programming) language represents a point on this figure. The distance to each of the corners represents the level of abstraction or the amount of obstacles between the language and the party in the corner.

There are some observations to be made merely from this geometric shape. First of all, as you get closer to one corner, you get away from the others.This also means that there is no point that is very close to all the corners. The center point, which might be intuitively considered the ‘ideal’ point, is actually not that close to any of the corners.

Now think of every point as a language. Interpreting the observations leads to interesting results. First, as language grows closer to one of machine, user, and problem, it inevitably gets farther away from the others. Resulting from this, there is no ‘perfect language’. There are tradeoffs and decisions to be made at every step of language design that influence the distance to either party. Also, a balanced language does not excel in closeness to any of the parties.

The weight of each of the parties can be adjusted with regard to the task at hand.

  • Put less weight towards the problem. Many tasks are algorithmically or computationally trivial, i.e. I/O-intensive operations.

  • Put less weight towards the user. If the solution is deemed to be a one-off quick fix, code that looks obfuscated might be acceptable. (Whether or not this is a good idea is another question.)

  • Put less weight towards the machine. If the solution is algorithmically complex, has many interactions with other software, or is not likely to be final, worse performance may be a good tradeoff.

Now, let’s start actually putting some languages on the map. Disclaimer: this probably is where you start disagreeing with me, if you haven’t already. The criteria are not set in stone, and “closeness to the user” is subjective anyway.2

User Problem Machine Assembler C BASIC RPG C++, Go English Ruby Python JS, Lua Java, PHP, Rust Math notation Haskell Erlang Lisp

With this choice of positioning, many general assumptions made about languages are fulfilled: Assembler is as close to the metal as it gets, but it’s hard to work with and modeling complex problems becomes a pain. Ruby and Python are easy to learn, can ‘solve problems’ quite well, but are slow because they abstract at lot from the machine. Even though math works best, Haskell can model complex algorithmic problems well and do so efficiently, but at the cost of intuitiveness for the author. Finally, liberal, balanced languages like Java have ‘a bit of everything’, but don’t orientate strongly in any direction. 3

In the past, program and programming language design was heavily influenced by the restricted performance of the computers of the time. A program that finishes before the universe collapses is better than one that doesn’t but reads like a poem, right?

I claim that the machine is going to have less and less of a central role for the design of the programming langugages that shape the future.

Now, with this statement I don’t want to insult everyone coding C, C++ or Java today. 4 Of course we can’t do computing without the computer. Every higher-level language needs to be translated (compiled or interpreted) to lower-level code eventually. But also, we can’t do meaningful computing without making it as easy as possible for humans to access, grasp and modify our programs. And in the future, this will become more important. As everything around us starts to become connected, the complexity of the interactions will rise faster than the complexity of the computations within a single unit.

In conclusion, no, it’s still not the tools that matter the most. It’s the one using them. But that doesn’t mean that carefully choosing the right tool won’t make your day a heck of a lot easier.

Oh, and trying to put Brainfuck onto that triangle nearly made my head explode.

  1. Or to bash BASIC, or to giggle at Go. 

  2. Between every two languages, there are probably hundreds more, unpictured. Also, English is used merely as a representative for every spoken language. 

  3. And the last one, “Languages outside the triangle are probably shitty.” 

  4. Well, actually, maybe the Java guys.