curayious Language Lab

Taxonomy — How Tracks Are Tagged

The problem with one axis

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.

Six axes instead

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 production

Not "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 is

procedural, 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 it

manual, 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 enough

static-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 you

none, 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 release

An 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.


Worked examples

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:

  1. 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.
  2. Erlang's per-process GC is a different thing from Java's GC, even though both are tagged 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.

Frontmatter

---
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.