The obvious tagging scheme is backend / frontend / fullstack / data, and it falls
apart on contact with the actual list:
"Full stack" is a career label — it describes a person's job, not a language's design. Applying it to languages produces a tag that is either wrong or vacuous.
Every track carries these in its frontmatter. They are orthogonal, so a track can be filtered or sorted on any one of them, and the comparison matrix is generated from them.
reach — where it plausibly runs in productionNot "where it can run" (everything can run everywhere if you try hard enough) but where a professional would reach for it without a justification meeting.
| Value | Meaning |
|---|---|
systems |
Kernels, drivers, runtimes, embedded — the layer below the application |
backend |
Server-side application and service code |
frontend |
Browser and native UI |
data |
Query, transform, analyse — the language of the store |
glue |
Scripts, pipelines, CI, the shell — small programs that wire other programs together |
batch |
Scheduled, file-in/file-out, no interactive user |
Multi-valued. C is [systems, backend]; Java is [backend, frontend] (Android counts);
SQL is [data]; Bash is [glue]; COBOL is [batch, backend].
paradigm — what the language thinks a program isprocedural, object-oriented, functional, actor, declarative, logic, array.
Multi-valued, and honest about it: modern C++ is [procedural, object-oriented, generic] and
pretending otherwise is how people end up writing Java in C++.
memory — who frees itmanual, gc, refcount, ownership, arena, none. Single-valued. This is the axis that
predicts the most about what it feels like to write large programs in the language.
typing — two sub-axes, because one is not enoughstatic-strong (Java, Rust), static-weak (C — an int becomes a char * with a cast and
no complaint), dynamic-strong (Python — 1 + "x" is an error), dynamic-weak (JavaScript —
1 + "x" is "1x"), gradual (TypeScript, Python with annotations).
The strong/weak distinction is the one people skip, and it is the one that explains why C and Java feel nothing alike despite both being "statically typed".
concurrency — the primitive the language gives younone, os-threads, green-threads, goroutines-channels, actors, async-await,
gil-limited, process-parallel. This is the Q6 answer compressed to one token.
era — the year of first releaseAn integer. Not decoration: it is the single best predictor of a language's defaults. Anything pre-1990 assumes ASCII and a single core. Anything post-2009 assumes UTF-8, many cores, and a package registry.
| Track | reach | paradigm | memory | typing | concurrency | era |
|---|---|---|---|---|---|---|
| C | systems, backend | procedural | manual | static-weak | os-threads | 1972 |
| C++ | systems, backend | procedural, OO, generic | manual, raii | static-strong | os-threads | 1985 |
| Rust | systems, backend | procedural, functional | ownership | static-strong | os-threads, async-await | 2015 |
| Java 8 | backend, frontend | object-oriented | gc | static-strong | os-threads | 1996 |
| Java 21 | backend, frontend | OO, functional | gc | static-strong | os-threads, green-threads | 1996 |
| Python | backend, data, glue | procedural, OO, functional | refcount, gc | dynamic-strong | gil-limited | 1991 |
| Go | backend, glue | procedural | gc | static-strong | goroutines-channels | 2009 |
| Erlang | backend | functional, actor | gc (per-process) | dynamic-strong | actors | 1986 |
| Elixir | backend | functional, actor | gc (per-process) | dynamic-strong | actors | 2011 |
| COBOL | batch, backend | procedural | static | static-strong | none | 1959 |
| SQL | data | declarative | none | static-strong | none | 1974 |
| Bash | glue | procedural | none | dynamic-weak | process-parallel | 1989 |
| TypeScript | frontend, backend | OO, functional | gc | gradual | async-await | 2012 |
Two things fall out of that table immediately, and neither is obvious from a list of language names:
memory and era are correlated, and the exception is the interesting one. Rust is
the only post-2009 language on the list that does not use a garbage collector, and
ownership is the entire reason it exists.gc. That is the taxonomy telling you where it is too coarse — and that is exactly
the sort of thing worth a paragraph in the Erlang track's Q3.---
title: "C — The Substrate"
slug: 10-c
num: "10"
section: "Arc I · Machine and memory"
status: done # done | wip | draft | planned
reach: [systems, backend]
paradigm: [procedural]
memory: manual
typing: static-weak
concurrency: os-threads
era: 1972
tags: [pointers, undefined-behaviour, make]
blurb: >
...
---
The site generator reads this directly; there is no second list to keep in sync. That is the
one structural improvement over the COBOL lab's build_site.py, where the reading list was
hardcoded in the script and drifted from the files within a week.