1 The Scoring Model

Companion to: The Great Language Smackdown · the Scoreboard · the Criteria

The main article ranks 65 languages by language-imposed coupling and by engineering readiness. This companion publishes the mechanism inventories, the arithmetic, and the tests that decide presence, so any reader can reproduce any number from first principles. The rules and the arithmetic are fixed; the weights and the clamp are authored judgments. The per-language data itself is on the Scoreboard.

What each mechanism means, what it forces to agree, and why it costs what it costs is explained in the Criteria.

The coupling analysis this model operationalizes — coupling as access to a shared resource, and the derivation of a modularisation directive from coupling — is developed in the published coupling papers [1], [2].

Analysis date: June 2026. All languages are assessed against the version shown.

1.1 How a score is computed

The model is a capped-sum-per-dimension inventory:

  1. A fixed mechanism inventory, each mechanism with a fixed weight.
  2. For each language, every mechanism is marked present or absent (a factual determination).
  3. Within each dimension of one axis, the present weights are summed and clamped to at most −15.
  4. Score = 100 − Σ(capped per-dimension contributions), computed per axis.

The cap equals the High weight (−15), so a dimension never costs more than one severe mechanism. This keeps scores bounded (a six-dimension axis never falls below 10), monotone (adding a mechanism never helps), and discriminative (no collapse to zero).

1.1.1 Score bands

Because the model is a fixed-inventory capped-sum-per-dimension model, the bands follow directly from the mechanism weights:

  • 90+: No dimension contains a severe (High) mechanism, and at most one dimension reaches even −8. Near the irreducible floor.
  • 75–89: No dimension reaches −15; a small number of moderate (−8) mechanisms spread across dimensions.
  • 60–74: At least one dimension caps at −15 (a severe mechanism), or several dimensions carry moderate mechanisms.
  • 45–59: Two or three dimensions cap at −15, or one severe mechanism plus several moderate across other dimensions.
  • Below 45: Three or more dimensions cap at −15 — the language’s design trades separation of concerns for other goals (simplicity, flexibility, ubiquity, or direct hardware access).

The readiness score uses the same arithmetic, over its six dimensions. Its bands are stated over the total it can actually reach: readiness has no High mechanism, so only Reproducibility and Governance can reach the clamp, and a readiness dimension caps only when two Moderate mechanisms meet. A readiness band is not comparable to a coupling band, because the two axes price different kinds of cost; the profile is never scored at all.

1.1.2 Dimension sub-scores

The comparison matrices show each dimension’s cost, not a percentage: 0 means no mechanism is charged, and a negative number is the cost. Each dimension is capped at −15 when it feeds the score, and where the cap bites the uncapped cost is shown in parentheses, so two languages at the cap stay distinguishable. A language’s Core score is therefore 100 minus the sum of its six capped costs, its Ecosystem score the same over its eight, and its Readiness score the same over its six; the cells in a matrix do not sum to the total because each is capped independently.

1.2 Mechanism inventory (weights)

1.2.1 Core — six dimensions

Dim Mechanisms (weight)
Type T1 dynamic no static check (−15), T2 weak static (−8), T3 dynamic/duck dispatch (−8), T4 no sum types (−4), T5 no generics (−4), T6 no namespaces (−8), T7 type erasure/reflection (−4), T8 operator overloading (−4), T9 inheritance required for polymorphism (−4), T10 no null-safety (−8), T11 no module boundary (−8), T12 no effect tracking (−8), T13 async/sync colouring (−8), T14 unchecked foreign boundary (−4)
Construction C1 global mutable state by default (−15), C2 no immutability by default (−4), C3 constructors coupled to allocation (−4), C4 no constructor/validation (−4)
Memory M1 manual deallocation (−15), M2 GC non-deterministic pauses (−8), M3 no RAII (−4), M4 no ownership model (−8)
Error Er1 no structured path (−15), Er2 unchecked exceptions only (−8), Er3 errors ignored/non-exhaustive (−4), Er4 no composable result type (−4)
Concurrency K1 GIL/no parallel (−15), K2 shared mutable state default (−8), K3 manual sync no race detection (−8), K4 no structured concurrency (−4), K5 no primitives (−4)
Platform P1 cannot function outside one vendor/domain (−15), P2 single-vendor but other uses (−8), P3 legacy/discontinued platform (−8)

1.2.2 Meta — eight dimensions

Dim Mechanisms (weight)
Performance R1 interpreted no AOT/JIT (−8), R2 GC pauses (−8), R3 JIT warmup (−4)
Ecosystem Ec1 no package manager (−4), Ec2 fragmented tooling (−8), Ec3 small/niche/discontinued (−8), Ec4 proprietary (−8), Ec5 platform-locked tooling (−8), Ec6 monoculture (−8), Ec7 legacy burden (−8)
Evolution V1 breaking changes (−8), V2 frozen (−4), V3 discontinued (−15), V4 glacial standards (−4)
Domain D1 domain/vendor lock-in (−15), D2 poor domain fit (−8), D3 framework forces architecture (−8)
Learning L1 steep (−8), L2 large surface/multi-paradigm (−4), L3 sparse docs (−4)
Syntax S1 verbose (−8), S2 inconsistent (−8), S3 punctuation-heavy (−4)
Testing G1 weak tooling (−8), G2 poor debugging (−8), G3 runtime-only errors (−4)
Security Q1 memory-unsafe (−15), Q2 dynamic/weak typing risk (−8), Q3 known vulnerability/injection (−8)

1.2.3 Readiness — six dimensions

Dim Mechanisms (weight)
Reproducibility Y1 build not reproducible (−8), Y2 dependencies not pinned (−8)
Supply chain Y3 no signed provenance (−8), Y4 registry without namespacing (−4)
Observability Y5 no stable tracing standard (−8), Y6 no structured logging (−4)
Feedback Y7 slow build (−8), Y8 no fast in-editor analysis (−4)
Interop Y9 no foreign-function interface (−8), Y10 no portable target (−4)
Governance Y11 single-vendor governance (−8), Y12 closed specification (−8)

Three scores, reported separately, and an unscored profile. The comparison reports Core coupling, Ecosystem coupling, and Engineering readiness as three separate numbers over the same capped-sum rule. They are reported separately and never summed: a language can be weakly coupled and hard to ship, or strongly coupled and easy to operate. Several mechanisms share one underlying fact across axes — a missing package registry affects both Ec1 and the supply-chain mechanisms — so the three scores are correlated in practice even though they are scored apart. Alongside them, the per-language profile records three axes the score deliberately does not price — energy and cost, AI and agent readiness, and safety certification — as evidence-backed notes, not numbers.

1.2.4 What counts as present

Presence is a factual determination about the language a programmer can write, not about a team’s house style or a third-party tool. Three coupling determinations need a stated rule:

  • A check behind a project switch. Some mechanisms depend on a compiler switch that the project file sets. The mark uses the configuration the language’s own project initialiser writes for the version shown, because that is what a new project gets without a decision. tsc --init writes "strict": true, and strict sets strictNullChecks, so TypeScript is not charged T10. dotnet new writes <Nullable>enable</Nullable>, so C# is not charged T10. Visual Basic’s compiler default is Option Strict Off and the SDK template sets no OptionStrict, so the narrowing conversion is charged T2. Where the initialiser writes no switch, the compiler default governs. A check that only a separate tool supplies is never counted — the mypy case under T1.
  • M2 — the collector’s schedule. Present when the run time reclaims memory on its own schedule rather than at the last reference, so the program cannot name when the heap shrinks. Deterministic reclamation is not charged: Swift’s ARC and Delphi’s strings and interfaces release at the last reference, and Delphi on Windows frees objects explicitly. Objective-C is charged, because an autorelease pool defers a release past the last reference and a Core Foundation handle is released by hand. The collector must be the one that reclaims the language’s own objects: a language that compiles to another scored language inherits that language’s collector (TypeScript inherits JavaScript’s), while a language whose artifact is consumed by a host rather than executed as its own objects is not charged here (a Rocq term is checked by the kernel, and a Scratch project runs inside the Scratch VM).
  • R2 — the collector’s pause. Present when the page records the collector’s pause as a cost the program must absorb — a ⚠️ or ❌ bullet on the pause itself, on a stop-the-world cycle, or on the program’s lack of control over the pause. Absent when the page names no collector cost at all, and absent when the page records the opposite (bounded collector steps, per-process collection, a collector mode stated as a strength). The mark is thus the page’s own assessment of its collector, which is what keeps the charge set checkable: where the page states the pause as a cost, the mechanism is charged.

A mitigation is not an absence. Some languages offer an opt-in construct that avoids a mechanism: @CompileStatic in Groovy, try-with-resources in Java, reified in Kotlin, a lint rule, or a flag the initialiser does not set. The mechanism stays charged. The default code still pays it, and avoiding it needs knowledge that the language does not force. That is deliberate: the model measures what the language imposes, not what a disciplined team can achieve with the same language. If a mitigation lowered the score, two teams on one language would score differently, and the language would have no score. The mitigation is recorded on the page as a strength or a trade-off, never as a discount. The line between a mitigation and an absence is the project-switch rule above: what a new project gets without a decision is the language’s; what the developer must know to turn on is a discipline.

The readiness axis is derived, not judged per language. Every readiness mechanism is a documented function of a fact about the language or its ecosystem — for example, “build not reproducible” is present when the language’s own build tool does not default to byte-reproducible output, and “no signed provenance” is present when the registry ships no default attestation. The tests are stated with each mechanism in the Criteria, so a reader can check a mark and regenerate the score.

1.3 How the tables are ranked

Every score on this site is reported on its own axis. The ranking score is the one place where two axes meet, and coupling leads it. The rule is declared here:

Term Role Why
Core Coupling Primary The coupling the language’s own constructs force into the code.
Engineering Readiness Modifier, capped at 15 points A toolchain, registry, and observability stack can be fixed by process; coupling written into the code cannot.
Ranking score core × (0.85 + 0.15 × readiness / 100) Readiness lifts the coupling score by at most 15%, so a full 0-to-100 readiness swing is worth 15 coupling points at the top — one High mechanism. Ties break on Core coupling, then readiness, then the name.

Ecosystem coupling does not enter the ranking. It is a dependency context, not a quality: a near-monoculture ecosystem lowers risk through consistency, so its band can disagree with its number (a language can score 84 there and 38 on Core). It stays a lens, and the table sorts by it, but it does not decide the order.

Coupling is primary; readiness is a modifier. Once the code is written, the code is what remains, and a maintainer faces it for most of a system’s life. A language that forces accidental coupling into every line has damaged that artifact permanently. Readiness surrounds the code rather than entering it, and it is remediable by process: a toolchain, a registry, and an observability stack can be fixed, while coupling in the code cannot. So readiness does not weigh against coupling as a peer.

1.4 How to reproduce a score

To reproduce any score: read the language’s present mechanisms for one axis, group by dimension, sum and clamp each dimension to −15, sum the clamped values, and subtract from 100. Repeat for each axis. The three axes are scored apart: no score is ever added to another, though several mechanisms share one underlying fact and the axes are correlated in practice.

Worked example — Java (Core 50): present Core = T7, T10, T12, T14, C2, M2, M3, M4, Er2, K3.

Dimension Present Clamped sum
Type T7(−4) + T10(−8) + T12(−8) + T14(−4) = −24 −15 (clamped)
Construction C2(−4) −4
Memory M2(−8) + M3(−4) + M4(−8) = −20 −15 (clamped)
Error Er2(−8) −8
Concurrency K3(−8) −8
Platform — 0

Total clamped = 15+4+15+8+8 = 50. Core = 100 − 50 = 50. ✓

1.5 Complete per-language data

The ranked table and the complete per-language mechanism-presence data are on the Scoreboard.


The formal development. The definitions, theorems, and proofs behind this page are published in:

All published papers

References

[1]
Y. Loth, “On the nature of coupling: All coupling as shared resource access.” Zenodo, Aug. 2026. doi: 10.5281/zenodo.21925122.
[2]
Y. Loth, “A self-contained derivation of the optimal modularization from coupling.” Zenodo, Aug. 2026. doi: 10.5281/zenodo.21925268.