The Great Language Smackdown: 65 Languages Through Three Lenses
Analysis date: June 2026. All languages evaluated against their latest stable version as of this date.
Most language comparisons focus on syntax, performance, or popularity. This one is different.
This analysis examines each language through three lenses: a coupling lens (how well does the language separate independent concerns and prevent unwanted coupling?), a readiness lens (can you rebuild the artifact, verify what you shipped, observe it, work in it quickly, connect it to other languages, and count on its governance?), and an unscored profile (what does it cost to run, how well do coding models and agents work in it, and is there a safety-certified path?).
| Axis | The question it answers |
|---|---|
| Core coupling | How much accidental coupling does the language force into the code itself? |
| Ecosystem coupling | What does the surrounding platform, tooling, and community cost? |
| Engineering readiness | Can the artifact be rebuilt, verified, observed, worked in quickly, connected, and governed? |
| Profile (unscored) | What does it cost to run, how well do coding models work in it, and is there a safety-certified path? |
Version scope: Every language is assessed against its latest stable standard or release as of June 2026 [1], [2], [3], [4], [5], [6], [7], [8], [9], [10]. Scores reflect modern idioms and current best practices for that version, not historical usage. Where a language has multiple widely-used versions with meaningfully different coupling properties, this is noted explicitly.
Scope. This is a language analysis with two scores and an unscored profile — coupling and engineering readiness, plus a profile — a topic distinct from the Independent Variation Principle (IVP). The coupling score measures how much language-imposed coupling each language inflicts on programs; the readiness score measures whether the artifact can be reproduced, verified, observed, worked in quickly, connected to other languages, and governed openly. None of the three identifies change drivers, computes driver assignments, or measures module cohesion; those belong to IVP and are outside this analysis. Each language has its own page with the full detailed evaluation; the sections below give the grouped results and rankings.
1 Quick Reference by Use Case
- Need maximum safety? → Rust, SPARK, Lean 4, Rocq, PureScript, Haskell, Ada
- Formal verification? → SPARK, Lean 4, Rocq (theorem provers)
- Building enterprise apps? → C#, Java, Kotlin, TypeScript
- Web development? → TypeScript, JavaScript, Python, Ruby, PHP
- Systems programming? → Rust, C, D, Zig, C++
- Data science/ML? → Python, R, Julia, MATLAB, SQL
- Scripting/automation? → Python, Bash, Zsh, Fish, PowerShell, Lua
- Learning programming? → Scratch, Python, JavaScript, Scheme
- Functional programming? → Haskell, OCaml, Elixir, F#, Clojure, Scheme, PureScript, Unison
- Game development? → C++, C#, Rust, D, Lua (scripting)
- Mobile apps? → Swift (iOS), Kotlin (Android), Dart (Flutter), C# (.NET MAUI)
- Fault-tolerant distributed? → Erlang, Elixir (BEAM/OTP)
- Cross-platform UI? → Dart (Flutter), Kotlin (Compose Multiplatform)
- Scientific/numerical? → Julia, Python, R, MATLAB, Fortran
2 What is coupling?
2.1 A coupling taxonomy: accidental vs. necessary
Coupling falls into two fundamental kinds:
| Kind | Definition | Origin |
|---|---|---|
| Necessary coupling | Dependencies the system cannot function without — the irreducible coupling floor. Causal dependencies dictated by the domain structure. | Domain artifacts |
| Accidental coupling | Dependencies that are not causally required — coupling that exists by developer choice, oversight, or language/platform constraint. | Design or platform |
In any system, necessary coupling is the minimum possible: the inter-module communication the domain demands. Accidental coupling is everything beyond that — coupling introduced by design choice, oversight, or the language and platform itself. This taxonomy, and the coupling-floor idea it rests on, is developed in the coupling analysis: the definition of coupling as access to a shared resource [11], and the coupling floor as the coupling the domain demands [12].
Accidental coupling subdivides into two subtypes, which are the core of this language analysis:
| Subtype | Definition | Fix |
|---|---|---|
| Avoidable accidental | Could be removed by better design within the language’s capabilities. The developer chose to couple unnecessarily. | Better design |
| Language-imposed | Unavoidable given the language’s constructs — the irreducible residuum of accidental coupling the language inflicts on all programs. Even optimal design cannot eliminate it. | Change language or version |
A language can also couple elements in dimensions beyond structural dependency. Coupling has several dimensions: structural, temporal, concurrency, security, platform, and language (memory model, type system, module system). Each dimension carries its own dependency relation, and coupling decomposes into necessary and accidental components.
What this means for language comparison: This article evaluates languages along the language coupling dimension: how much language-imposed coupling does the language generate, and how well does it help you detect and eliminate avoidable accidental coupling? A language with a good coupling profile (a) minimizes language-imposed coupling (fewer constructs that force accidental edges) and (b) detects avoidable coupling at the earliest possible stage (compile time > static analysis > runtime > never).
The coupling scores answer: how close does this language let you get to the irreducible coupling floor? The readiness score answers a separate question, stated with it below. The profile is not scored. The ranking score is coupling, lifted by at most 15% for readiness — coupling is primary, because the code is what remains and readiness is remediable by process. The rule is stated on the Scoring Model.
3 How the Scores Are Computed: Methodology
Every language imposes some amount of accidental coupling that even optimal design cannot eliminate. Headers force compilation coupling. Unchecked null forces null-check coupling. A global interpreter lock forces concurrency coupling. Dynamic typing forces coupling detection to runtime. These are not design mistakes — they are language properties.
The scores in this analysis are computed by a fixed, mechanical rule, not by subjective impression:
- A closed mechanism inventory — each coupling mechanism has a fixed weight.
- A binary presence check — for each language, each mechanism is marked present or absent (a factual determination, not a severity judgment).
- An arithmetic rule — within each dimension the present weights are summed and capped at −15 (one severe mechanism’s worth), and the score is 100 − Σ(capped per-dimension contributions).
Because the weights are fixed and the only per-language step is present/absent, any two analysts following these rules reach identical scores. The framework makes disagreement precise: to dispute a score, you must either contest a mechanism’s presence in a specific language, or propose changing a fixed weight and then recompute.
The full mechanism inventory (Core coupling: Type, Construction, Memory, Error, Concurrency, Platform; Ecosystem coupling: Performance, Ecosystem, Evolution, Domain, Learning, Syntax, Testing, Security; Engineering readiness: Reproducibility, Supply chain, Observability, Feedback, Interop, Governance), the detailed capped-sum rule, and the tests that decide presence are on The Scoring Model. The ranked tables, the per-dimension sub-scores, and the complete per-language mechanism-presence data for all 65 languages — so any score can be reproduced from first principles — are on The Scoreboard.
What each mechanism means — what it is, what it forces to agree, how harmful it is, and why it removes the points it removes — is explained mechanism by mechanism, with examples, in the Criteria.
Three scores, not one. The comparison reports Core coupling (what the language’s own constructs force), Ecosystem coupling (what the surrounding platform, tooling, and community cost), and Engineering readiness (whether the artifact can be rebuilt, verified, observed, worked in quickly, connected to another language, and governed openly). The three scores are reported separately and are never summed. They are correlated in practice — a missing package registry affects both Ecosystem coupling and the supply chain — but each is scored on its own axis. Alongside them, an unscored profile records three axes a score cannot price — energy and cost, AI and agent readiness, and safety certification — language by language.
3.1 What the coupling score means
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).
No language reaches the 90+ band today. That band is an ideal, not a description of the field: it means no dimension carries a severe mechanism and at most one reaches even −8. The current languages have not met that bar, and the gap to it is the progression margin left to language design.
3.2 What the readiness score means
The readiness score uses the same arithmetic over its six dimensions, but its bands are different. Readiness has no High mechanism, so a dimension caps only when two Moderate mechanisms meet, and its bands are stated over the total it can actually reach. A readiness band is therefore not comparable to a coupling band. The readiness bands are listed with the coupling bands under “By Score” below, and on the Scoreboard.
4 1. Type System Powerhouses
5 2. Modern Mainstream
6 3. Systems and Performance
7 4. Dynamic and Scripting
8 5. Shells and Automation
9 6. Functional, Declarative, Legacy
- Common Lisp (ANSI)
- Prolog (SWI 9.4)
- Fortran (2023)
- Ada (2022)
- SPARK (Pro 25)
- Lean 4 (4.31)
- Rocq (9.0)
- OCaml (5.4)
- Clojure (1.12)
- Racket (8.17)
- Scheme (R7RS)
- Smalltalk (ANSI)
- Tcl (9.0)
- Lua (5.5)
- Delphi (12.3)
- Visual Basic 16 (.NET)
- COBOL (1989:2023)
- Objective-C (2.0)
- Turbo Pascal (7.0)
- VBScript (6.0)
10 7. Domain-Specific Languages
11 8. Educational and Special
12 9. Emerging and Specialty
13 The Scoreboard
Every score in the comparison — the ranked table, the three per-dimension matrices, and the complete per-language mechanism data — is on the Scoreboard.
14 Summary and Recommendations
14.1 How to Use This Analysis
By Paradigm:
- Type System Powerhouses → Maximum safety, steep learning curves
- Modern Mainstream → Best balance for most projects
- Systems and Performance → When you need low-level control
- Dynamic and Scripting → Rapid prototyping, flexibility over safety
- Domain-Specific → Perfect fit for specialized problems
By Score (latest version, modern idioms):
Coupling bands, over the Core score
- 90+ (0): —
- 75–89 (8): Rocq, Rust, SQL, Unison, Lean 4, Ada, Swift, Haskell
- 60–74 (8): SPARK, Elixir, Erlang, PureScript, Clojure, Racket, Scheme, Zig
- 45–59 (22): OCaml, Tcl, Transact-SQL, D, Prolog, Scratch, Dart, F#, SAS, C++, Crystal, Java, Kotlin, Scala, Solidity, COBOL, Common Lisp, R, Smalltalk, C#, Eiffel, Visual Basic
- below 45 (27): Bash, C shell, Delphi, Fish, Go, Ksh, Lua, Nim, PowerShell, Sh, Zsh, Objective-C, VBScript, MATLAB, PL/SQL, Turbo Pascal, Groovy, Fortran, Julia, Python, JavaScript, PHP, Perl, Ruby, TypeScript, C, Assembly
Readiness bands, over the readiness score
- 90+ (3): Go, JavaScript, TypeScript
- 75–89 (12): C#, F#, Ruby, Visual Basic, Java, Scala, PHP, Groovy, Python, Kotlin, SQL, Unison
- 60–74 (30): Dart, Elixir, Erlang, Nim, Zig, Clojure, Swift, Assembly, Bash, Crystal, Fish, Julia, Rust, C, C++, D, Fortran, Perl, C shell, Ksh, Lean 4, PureScript, Sh, Zsh, COBOL, Lua, OCaml, PowerShell, R, Transact-SQL
- 45–59 (15): Ada, Common Lisp, Eiffel, Racket, Scheme, Smalltalk, VBScript, Scratch, Solidity, Haskell, Objective-C, Prolog, Tcl, Rocq, PL/SQL
- below 45 (5): MATLAB, SPARK, Turbo Pascal, Delphi, SAS
15 The Verdict: Coupling Edition
Ranked by Core coupling from the model (capped-sum-per-dimension); the numbers behind every grouping below are on the Scoreboard. Analysis date June 2026 — older versions of the same language can score significantly lower (e.g., C++98, Java 8).
If you need mathematical proof of correctness: Rocq, SPARK, Lean 4
If you want bulletproof low coupling by language design: Unison, Rocq, Rust, SQL
If you want low coupling with pragmatism: Haskell, PureScript, Zig, OCaml
If you want low coupling with discipline (modern versions): Elixir, Erlang, Clojure, Transact-SQL, Dart, Kotlin, Delphi, Go
Low coupling on a budget (ecosystem-driven): Tcl, F#, Scala, C++
Specialized excellence (unique coupling profiles): Erlang: Actor model with per-process isolation and let-it-crash. Elixir: Modern BEAM with macros and protocols. Julia: Multiple dispatch without inheritance. Eiffel: Design by Contract states each routine’s obligations in the source. Objective-C: Dynamic messaging plus categories, protocols, and blocks for decoupling. Turbo Pascal: Units give genuine interface/implementation separation rare among 1980s languages.
Domain-locked procedural database logic: PL/SQL and Transact-SQL couple all logic to their database engines but offer real encapsulation (packages/spec-body, stored procedures) and structured exceptions. SAS uniquely separates the DATA step from PROC steps. Use them only where the logic must live inside the database or analytics engine.
Lowest forced coupling:
- Unison: Content-addressed code, algebraic effects, distributed computing built-in
- Rocq: Machine-checked proof as the unit of development
- Rust: Ownership enforces separation, Result types compose, no null, traits decouple
- SQL: Declarative, no in-language coupling among your elements
- Lean 4: Dependent types over a small trusted kernel
Low coupling with pragmatism (latest versions):
- Haskell: Type classes, explicit effects, immutability
- PureScript: Effect system separates effect types
- Zig: Explicit everything, error unions, allocator parameters, comptime
- OCaml: Module system, immutable data, exhaustive pattern matching
Highest forced coupling:
- Assembly: No abstractions, manual everything, maximum coupling risk
- C: Manual memory, weak typing, global state, undefined behavior
- JavaScript: Dynamic, global state, unchecked errors, no types
- Perl: Dynamic, global state, primitive objects, GIL
- PHP: Dynamic, weak typing, superglobals, no concurrency
- Ruby: Dynamic, global state, metaprogramming everywhere
- TypeScript: JavaScript’s runtime coupling under a compile-time type layer
Neither helps nor hinders coupling:
- C: With discipline, coupling can be low; without it, coupling is extreme
- D: Better C++ with cleaner templates, contracts, and both GC and manual memory
16 The Real Truth
Coupling scores depend heavily on which version of a language you’re using. C++23 is a fundamentally different language from C++98. Java 26 with records, sealed classes, and virtual threads is not the same as Java 8. Always check the version baseline.
Version aside, Coupling scores don’t determine project success. Context matters:
- Team expertise trumps language coupling score
- Ecosystem maturity often beats language elegance
- Hiring availability is a real constraint
- Performance requirements eliminate choices
- Platform constraints narrow the field
But here’s what coupling analysis reveals:
Languages with proven separation (Lean 4, Rocq, SPARK) let a machine check a claim against a stated specification. The remaining risk moves to the specification, and the learning curve is steep.
Languages with enforced separation (Rust, Haskell, PureScript, OCaml) make coupling impossible to hide. You pay upfront in learning curve, gain long-term in maintainability.
Languages with optional separation (Swift, Kotlin, C#, modern Java, modern C++, Eiffel, Groovy) let you choose coupling level. Good for migration, requires discipline.
Languages with manual separation (C, D, Zig, COBOL, Turbo Pascal) put the separation burden on the programmer: the same language supports a carefully separated design and a tangled one. Expertise required.
Languages with runtime-only separation (JavaScript, TypeScript, Python, PHP, Ruby, shells, VBScript) defer most coupling detection to testing. TypeScript moves a share of that detection to compile time, but its runtime coupling is JavaScript’s. Python 3.14 (free-threaded), PHP 8.4 (property hooks, fibers), and Ruby 4.0 (YJIT, pattern matching) have all made meaningful coupling-separation progress in recent versions.
Languages with domain-locked separation (Objective-C, PL/SQL, Transact-SQL, SAS, Solidity) are coupled to a single platform or domain — the platform is the unit boundary, and the language’s coupling quality only matters within it.
One result worth stating plainly: TypeScript now scores exactly what JavaScript scores. The type layer genuinely removes coupling — strict makes absence a checked case, and structural typing, union types, and generics remove the dynamic-typing mechanisms — but the per-dimension clamp maps both to the same Type sub-score. The difference is in the presence lists: JavaScript carries T1, T4, T5, and T10; TypeScript carries T7. A reader who wants the type-layer difference must read the presence table, because the score does not carry it.
The lesson: Match language coupling capabilities to your context AND your version. C++23 with modern idioms is a different beast from C++98. Java 26 with virtual threads, records, and sealed classes is not Java 8. Don’t pick a language based on its worst version. Building life-critical systems? Use SPARK or Lean 4. Building a 20-year system with changing requirements? Invest in Rust. Building mobile apps? Swift or Kotlin. Building a weekend project? JavaScript is fine. Maintaining legacy code? TypeScript adds compile-time detection incrementally, though its runtime coupling is JavaScript’s. Need shell automation? PowerShell adds objects, Fish adds interactive polish, and Bash stays the portable default.
No language is best in every context. The scores show where a language matches your constraints and where it will charge you; design covers the rest.
The evidence points away from a single winner: different contexts need different coupling trade-offs, and the scores price them.
The scores are a starting point. The design work is yours.
17 Learn More
The coupling account this analysis rests on is developed in the published coupling papers:
- On the Nature of Coupling: All Coupling as Shared Resource Access [11] defines coupling as access to a shared resource, with the resource taxonomy and the three coupling modes.
- A Self-Contained Derivation of the Optimal Modularization from Coupling [13] derives the modularisation directive from the coupling account alone.
- Coupling as a Consequence of Cohesion: Decomposition, the Coupling Floor, and Domain-Imposed Coupling [12] establishes the coupling floor and shows that correctly bounded coupling is a consequence of cohesion.
The link to knowledge — why a language that scatters or hides a module’s knowledge imposes coupling — is the knowledge-embodiment theorem: a maximally cohesive module embodies exactly the knowledge its class must hold. The theorem, with the purity–completeness pair that measures it, is developed in On the Nature of Cohesion: Cohesion as Correctness Relative to a Partitioning Rule [14], with the causal grounding in Causal Cohesion [15].
Which language’s coupling analysis surprised you? Which mechanisms did the analysis miss? Share your experience in the comments.
The formal development. The definitions, theorems, and proofs behind this page are published in:
- On the Nature of Coupling: All Coupling as Shared Resource Access — Zenodo, 2026 — doi:10.5281/zenodo.21925122
- A Self-Contained Derivation of the Optimal Modularization from Coupling — Zenodo, 2026 — doi:10.5281/zenodo.21925268
- Coupling as a Consequence of Cohesion: Decomposition, the Coupling Floor, and Domain-Imposed Coupling — Zenodo, 2026 — doi:10.5281/zenodo.21925201
- On the Nature of Cohesion: Cohesion as Correctness Relative to a Partitioning Rule — Zenodo, 2026 — doi:10.5281/zenodo.21703193
- Causal Cohesion — Zenodo, 2026 — doi:10.5281/zenodo.21703156