pick a level to filter, drag for a range
Explanation
I know comparisons on PLs could be very controversial, but I want to make clear that this chart is intentionally biased to represent my world of view.
-
The Y axis represents my experiences, ranging from little (🤦♂️), school-level (🙇♂️), industry-capable (👨💻), towards language lawyer (👨🎓). This should be less controversial. Well, except for my professors or colleagues who reviewed my code and decided that my code is shittier than I thought.
-
The X axis is how interesting a PL to me, ranging from boring (🥱), cool (😎), nerdy / love-it (🤓), mind-blown / obsessive (🤯). Although this is very subjective, my subjectivity does show some correlations with objectivity such as theoretical interestingness (e.g.
Coq/Agda > OCaml/Haskell) and standard advancements (e.g.C++0x > C++,Typed JS > ES6 > JS). So it could feels controversial when people mistaking the chart as "Oh how is OCaml considered superior thanyour favorites in the chart?". Well, the reason could be as simple as "It related to my job (or not)!", or "I have no time to dig into it currently!". So don't take it too serious, and I will try to explain (in the tooltips) when I could. -
The colors are trying to capture the abstraction level. This is the most objective and measurable one, and I admit that my ordering is absolutely inaccurate and could be very misleading: e.g.
- C++/Rust can be as low as C and as high as many at the same time!
- Java and Scala are compiled into the exact same set of JVM instructions!
A refined definition should use a range but then I don't know how to visualize them in a chart. So instead, I had to used a value. But it come with some reason and not totally irrational:
-
A balance of their stereotypes and to emphasize what made the most differences, e.g.
- Zero-overhead abstraction made C++/Rust more capable for system programming.
- Being more managed (e.g. GC-ed) would be given higher abstraction level.
-
Their type system, this one is very tricky though:
- From theory, we learned that the set of programs expressible is always narrowed because of incompleteness, so types sacrificed some dynamic semantics and could take away abstraction powers.
- Yet type system enrich the static semantics and enable another level of abstractions, e.g. (higher-order) type operators abstract types just as (higher-order) functions abstract terms, thus adding abstraction powers.
I don't know if a well-defined total order exist. The partial order I ended up with is letting the untyped PLs sitting in the middle, with whose type system are more traditional towards lower and those with more advanced ones (e.g. gradual, inductive, higher-ranked, higher-kinded, dependently-typed) towards higher.
Put another way, what the colours measure is who a language's design serves. Types can serve the machine — int, class, layouts a compiler can map onto hardware — or the mathematics: algebraic data types, parametric polymorphism, dependent types, all the way to proof assistants, where the types are the computation. That is why the statically typed mainstream sits at 4, just below the untyped middle, and why the top climbs toward the λ-calculus (and, for Prolog, logic). And it is the designers' intention that counts: what a language grew into later, or stumbled upon — C++'s template metaprogramming was discovered, not designed — does not move it much. A type can promise a lot or a little, and the promise can be kept by a proof, by a check at run time, or by no one; from 7 up, it is kept by the proof.
Where one value undersells a language, it carries a range too: hover a dot, or open its note, to see how far it reaches. Natural language, added in 2026, spans the whole scale.