"Which language is better than C?"
That's an interesting question, but it's not even worth answering.
The correct question is:
"Which languages can occupy C's position in the software stack?"
The reason: C is far more than just a syntax. It is the binary and organisational substrate of modern computing. Every kernel, every runtime, every Python module, every shared library — they all pass through C at some point.
So "replacing C" means replacing that role, not just writing nicer code.
This essay examines C against thirteen "challenger" languages that are known — by their communities or by observers — as C-adjacent, low-level or C successor candidates.
We applied a systematic methodology using five filters to identify which ones are genuinely competing for C's throne — and which ones are solving different problems entirely.
What C actually is
C has been reigning champ of low-level procedural programming for over 50 years. You can think of it as having an alias-centric memory model — a metaphor, not a formal model, but a useful one.
Its defining axiom is:
Memory is bytes; pointers alias; mutation is unrestricted.
Everything else follows from that.
The compiler cannot assume anything about pointer targets. Mutation is always dangerous; undefined behaviour is unavoidable; and concurrency is hostile by default.
C's power comes from unrestricted aliasing. C's fragility also comes from unrestricted aliasing.
C is nonetheless:
- The ABI lingua franca
- The OS interface
- The library boundary
- The toolchain anchor
C is the dangerous uncle everyone still invites to dinner — because he owns the house.
The "C-family" illusion
What we call the "C family" is really:
A shared grammar sitting on top of incompatible execution models.
C-family syntax means braces, semicolons, infix operators, if (…), for (…), while (…), and block-scoped variables. These define a parser-level classification but not a semantic one.
Java, Rust, Zig, Go and C# look related because their keywords, braces and semicolons are so similar. But they are not related at the level that matters: aliasing, lifetime and memory ownership.
The economic reason is simple: C syntax is the QWERTY keyboard of programming. Changing it raises training cost without improving machine-level behaviour.
C syntax won; C semantics didn't. Every major descendant kept the braces but rewrote the rules underneath.
The four real semantic families
Once you strip syntax away, all C-inspired languages fall into four execution models, defined by who controls memory and aliasing.
| Model | Who owns memory? | Who enforces safety? | Examples |
|---|---|---|---|
| Unmanaged | Programmer | Nobody | C, C++, Zig, Odin, Hare, C3, Carbon, Jai |
| Hybrid | Programmer + runtime | Partial | D, Nim, V, Swift |
| Managed | Runtime | GC | Go |
| Verified | Compiler | Type system | Rust |
(Languages like Java, C#, and JavaScript also fall into the Managed category, but they don't claim to be C replacements, so we exclude them from this analysis.)
Important caveat: These buckets are coarse. They describe the default execution model, not every possible subset mode. D in -betterC mode behaves differently from idiomatic D; Swift in Embedded mode behaves differently from standard Swift. The taxonomy captures where each language's gravity pulls you, not where heroic effort can push you.
The five filters a real C-successor must pass
A language must be able to:
| Filter | Why it matters |
|---|---|
| Freestanding compilation | Kernels, firmware, runtimes |
| Deterministic layout | Structs and ABI are contracts |
| Stable C interop | The world is already written |
| No mandatory runtime | You must own the process |
| Toolchain-level visibility | Debuggers, profilers, sanitizers |
Most languages die here.
Critical distinction: A language passes these filters if its default compilation mode meets them, or if a first-class, maintained mode exists that does. Languages requiring unofficial hacks, unmaintained forks, or heroic effort to achieve freestanding operation do not pass.
The candidate pool
Here are the fourteen languages we'll evaluate. Each is discussed in public discourse as C-adjacent, low-level, or a potential C successor. Listed with core philosophy, semantic family, and a characterisation.
| Language | Year | Philosophy | Semantic family | Characterisation |
|---|---|---|---|---|
| C | 1972 | "Trust the programmer" | Unmanaged | The dangerous uncle who owns the house |
| C++ | 1985 | "Zero-cost abstractions" | Unmanaged | C's midlife crisis |
| Rust | 2015 | "Make invalid states unrepresentable" | Verified | Your compiler's disappointed parent |
| Zig | 2016 | "No hidden control flow, no hidden allocations" | Unmanaged | C's responsible older brother |
| Odin | 2016 | "The joy of programming, distilled" | Unmanaged | C for people who ship video games |
| Hare | 2022 | "Stability is a feature" | Unmanaged | C if Dennis Ritchie had a time machine |
| C3 | 2019 | "Evolution, not revolution" | Unmanaged | C with a sensible haircut |
| D | 2001 | "C++ without the baggage" | Hybrid | The language that tried to please everyone |
| Nim | 2008 | "Write like Python, run like C" | Hybrid | Python wearing a C costume to a job interview |
| V | 2019 | "Simple, fast, done" | Hybrid | The language of bold promises |
| Swift | 2014 | "Safety without sacrifice" | Hybrid | Objective-C's attractive replacement |
| Go | 2009 | "Simplicity scales" | Managed | Java in a hoodie |
| Carbon | 2022 | "C++ migration path" | Unmanaged | Google's C++ apology letter |
| Jai | ~2014 | "Game programmers know best" | Unmanaged | The language equivalent of "coming soon" |
C is the baseline. The other thirteen are the challengers.
Scope note: This analysis restricts itself to C-adjacent languages actively discussed as C successors in modern discourse. It excludes Ada/SPARK, Pascal variants, and other capable low-level languages that aren't typically framed as "C replacements" in contemporary conversation. That's a scope choice, not a quality judgement.
The defining axioms
Each language can be summarised by what it believes about memory. But first, six definitions:
- Memory: A flat array of addressable bytes. In C's model, any byte can be read or written if you have its address.
- Pointer: A value that holds a memory address. Pointers let you indirectly access and modify data elsewhere in memory.
-
Aliasing: When two or more pointers refer to the same memory location. If
pandqboth point to address0x1000, writing throughpchanges whatqsees. This is powerful and dangerous. - Mutation: Changing the value stored at a memory location. Unrestricted mutation means any code with a pointer can modify that memory at any time.
- Lifetime: The span during which a piece of memory is valid to access — from allocation to deallocation. In C, the programmer tracks lifetimes manually; use-after-free bugs occur when code accesses memory whose lifetime has ended.
- Ownership: The responsibility for a piece of memory's lifecycle — who allocates it, who may access it, and who deallocates it. In C, ownership is a convention. In Rust, ownership is enforced by the compiler: every value has exactly one owner, and memory is freed when the owner goes out of scope.
C's defining axiom combines the first four: memory is bytes, pointers can alias freely, and mutation is unrestricted. Lifetimes and ownership are the programmer's problem. Every C-inspired language must decide whether to keep, constrain, or replace that axiom.
| Language | Axiom |
|---|---|
| C | "Memory is bytes; pointers alias; mutation is unrestricted" |
| C++ | "Memory is bytes; pointers alias; mutation is unrestricted; also here are 47 ways to abstract over that" |
| Rust | "Memory is owned; aliasing is controlled; mutation is permissioned" |
| Zig | "Memory is bytes; pointers alias; but we will tell you when you mess up" |
| Odin | "Memory is bytes; pointers alias; but the defaults should be sensible" |
| Hare | "Memory is bytes; pointers alias; but the language should be finished" |
| C3 | "Memory is bytes; pointers alias; but the syntax shouldn't fight you" |
| D | "Memory is whatever you want it to be today" |
| Nim | "Memory is managed unless you insist otherwise" |
| V | "Memory is managed but we're working on making it optional" |
| Swift | "Memory is reference-counted; aliasing is... complicated" |
| Go | "Memory is the runtime's problem, not yours" |
| Carbon | "Memory is bytes; pointers alias; but we're fixing C++'s mistakes" |
| Jai | "Memory is bytes; pointers alias; and we'll ship when we ship" |
The C-ness comparison
How close is each language to C's actual execution model?
Scoring rubric:
- C-like syntax: Braces, semicolons, infix operators, familiar keywords
- C-style pointers idiomatic: Pointer arithmetic, manual aliasing, and explicit address manipulation are normal usage patterns
- Safety checks optional: Bounds checking, null checks, and similar guards can be disabled or are off by default
- Manual control: Programmer controls allocation, layout, and teardown without runtime intervention
Five stars means "basically C". Overall = minimum of the four columns (a language is only as C-like as its weakest dimension).
| Language | Syntax | Pointers | Safety | Control | Overall |
|---|---|---|---|---|---|
| C | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| C++ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐☆ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐☆ |
| Zig | ⭐⭐⭐⭐☆ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐☆ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐☆ |
| Odin | ⭐⭐⭐⭐☆ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐☆ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐☆ |
| Hare | ⭐⭐⭐⭐☆ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐☆ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐☆ |
| C3 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐☆ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐☆ |
| Carbon | ⭐⭐⭐⭐☆ | ⭐⭐⭐⭐☆ | ⭐⭐⭐⭐☆ | ⭐⭐⭐⭐☆ | ⭐⭐⭐⭐☆ |
| Jai | ⭐⭐⭐⭐☆ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐☆ |
| D | ⭐⭐⭐⭐☆ | ⭐⭐⭐☆☆ | ⭐⭐☆☆☆ | ⭐⭐⭐☆☆ | ⭐⭐☆☆☆ |
| Nim | ⭐⭐⭐☆☆ | ⭐⭐☆☆☆ | ⭐⭐☆☆☆ | ⭐⭐☆☆☆ | ⭐⭐☆☆☆ |
| V | ⭐⭐⭐⭐☆ | ⭐⭐☆☆☆ | ⭐⭐☆☆☆ | ⭐⭐☆☆☆ | ⭐⭐☆☆☆ |
| Swift | ⭐⭐⭐☆☆ | ⭐⭐☆☆☆ | ⭐☆☆☆☆ | ⭐⭐⭐☆☆ | ⭐☆☆☆☆ |
| Rust | ⭐⭐⭐⭐☆ | ☆☆☆☆☆ | ☆☆☆☆☆ | ⭐⭐⭐⭐☆ | ☆☆☆☆☆ |
| Go | ⭐⭐☆☆☆ | ☆☆☆☆☆ | ☆☆☆☆☆ | ⭐☆☆☆☆ | ☆☆☆☆☆ |
Key insight: Zig, Odin, Hare, C3, and Jai are C-family in physics. Rust is C-family only in grammar.
Note: C++ does not have a stable C ABI; and the C ABI cannot handle templates, overloads or name-mangling - so C++ cannot substitute for C.
How C-like languages diverged
Every descendant of C had to decide what to do about C's aliasing axiom. They took four different paths.
Path A — Keep C's physics
Languages: C++, Zig, Odin, Hare, C3, Carbon, Jai
They kept pointer aliasing, manual lifetimes, and undefined behaviour as a feature (or at least as an explicit tradeoff). They only changed ergonomics, not semantics.
These are C-family in physics.
(Some of these keep C's physics but still fail the five filters for non-technical reasons: maturity, release status, or scope. Carbon targets C++ migration; Jai isn't released. Semantic similarity doesn't guarantee practical usability as a C successor.)
Path B — Hide C's physics
Languages: Go (and outside our candidate pool: Java, C#, JavaScript)
They removed pointer arithmetic, explicit lifetimes, and alias control. They replaced them with tracing garbage collection, moving heaps, and runtime checks.
These are managed VMs with curly braces. They look like C but execute like Java.
Path C — Half-escape
Languages: D, Nim, V, Swift
They offer raw pointers when you ask, GC or ARC when you don't, plus slices and bounds checking. This creates two languages inside one compiler.
They are not C and not safe. They rely on discipline plus runtime support.
Path D — Replace the memory model
Languages: Rust
Rust throws away C's axiom — "Memory is bytes; pointers alias; mutation is unrestricted" — and replaces it with: "Memory is owned; aliasing is controlled; mutation is permissioned."
That is a new machine model, enforced at compile time.
Rust does not make C safer. It makes a different kind of machine that happens to use C syntax.
Applying the five filters
We now take all fourteen languages and run them through the five filters. C is the baseline — it passes by definition. The other thirteen are sorted into three tiers.
Tier 3: Clear failures
These languages have fundamental design conflicts with substrate programming, or cannot be evaluated.
Go — "Simplicity scales"
Characterisation: Java in a hoodie
Go fails the "no mandatory runtime" and "freestanding" filters. It has a mandatory garbage collector, mandatory runtime scheduler, and goroutine stack management that requires runtime support.
This means Go cannot occupy C's substrate role. It can, however, occupy a different and valuable role.
The distinction matters:
- Freestanding substrate programming = you control the machine (kernels, drivers, firmware, runtimes). No runtime beneath you.
- Systems infrastructure programming = you build infrastructure software (containers, networking, CLI tools). Runtime handles memory and scheduling.
Go is excellent at systems infrastructure. Docker, Kubernetes, and countless networking tools prove this. But Go is structurally incapable of freestanding substrate work.
Illustrative example: Imagine a hardware interrupt with a ~10μs deadline. A garbage collector that might pause for milliseconds cannot coexist with that constraint. This isn't a criticism of Go — it's a category distinction. Go solves different problems.
Go replaces C in infrastructure. It does not compete for C's substrate role.
Carbon — "C++ migration path"
Characterisation: Google's C++ apology letter
Carbon's publicly stated focus is C++ interoperability and migration. It is not positioned as a freestanding substrate language today.
Carbon is a C++ successor, not a C successor. Different problem.
Jai — "Game programmers know best"
Characterisation: The language equivalent of "coming soon"
Not publicly released. No stable toolchain. Cannot be evaluated against filters.
C++ — "Zero-cost abstractions"
Characterisation: C's midlife crisis
C++ passes the technical filters — it has freestanding mode, deterministic layout, and full toolchain support. But C++ is not trying to replace C; it's trying to extend C. It occupies a different niche: large-scale application development with object-oriented and generic programming.
C++ is C's companion, not its successor.
Tier 2: Conditional passes
These languages can pass the filters, but only when compiled in a restricted mode that disables significant features.
D (with -betterC) — "C++ without the baggage"
Characterisation: The language that tried to please everyone
BetterC mode removes the GC, runtime, classes, exceptions, dynamic arrays, associative arrays, nested functions with context, and most of the standard library (Phobos). What remains is closer to "C with templates" than idiomatic D.
D's tragedy is that it's genuinely well-designed, but arrived too early (before Rust proved the market) and tried to be too many things. In BetterC mode, C++ plus garbage collection becomes just C with better syntax.
Verdict: Passes filters, but the mode strips so much that it's debatable whether "D" is being used or a D-shaped subset.
Nim (with manual configuration) — "Write like Python, run like C"
Characterisation: Python wearing a C costume to a job interview
Nim can be pushed toward freestanding and embedded targets, but it becomes a "bring-your-own-runtime-stubs" exercise. Debugging largely happens at the generated-C level. The ABI is the underlying C compiler's, not Nim's.
Nim is better understood as a C producer than a C successor. It doesn't replace C; it generates it.
Verdict: Technically achievable. Philosophically awkward.
Swift (with Embedded Swift) — "Safety without sacrifice"
Characterisation: Objective-C's attractive replacement
Swift has an experimental Embedded Swift compilation mode that produces standalone object files with no runtime required. It disables reflection, existentials, and ABI stability. It primarily targets ARM and RISC-V embedded platforms.
This is genuinely interesting. But Embedded Swift is experimental, and Apple's priorities are phones, not kernels.
Verdict: Passes filters in experimental mode. Ecosystem and tooling are nascent. Worth monitoring.
V (with -gc none) — "Simple, fast, done"
Characterisation: The language of bold promises
V has a manual memory management mode and community members have built experimental kernel projects. But V's autofree — its main selling point — is experimental and not production-ready. The language is pre-1.0.
V promised a lot. The jury is still out on delivery.
Verdict: Technically passes. Maturity concerns.
Tier 1: Clear passes
These languages pass all five filters in their default or primary compilation mode. Their distinctive features remain available when targeting the substrate.
Rust — "Make invalid states unrepresentable"
Characterisation: Your compiler's disappointed parent
Axiom: "Memory is owned; aliasing is controlled; mutation is permissioned"
What it really is: A safe systems language wearing C syntax as a compatibility layer.
Rust's no_std mode is first-class. The borrow checker works without the standard library. In December 2025, kernel maintainers agreed Rust support is no longer "experimental".
In safe Rust, the compiler enforces aliasing and lifetime rules that eliminate use-after-free and data races. This guarantee applies to safe code; unsafe blocks and FFI boundaries are the programmer's responsibility.
Trade-off: Borrow checker complexity. Steep learning curve. Interop with C requires unsafe blocks.
Zig — "No hidden control flow, no hidden allocations"
Characterisation: C's responsible older brother
Axiom: "Memory is bytes; pointers alias; but we will tell you when you mess up"
What it really is: C with a compiler that cares.
Zig has no runtime by default. It can replace not just C code but the C toolchain — it works as a drop-in C compiler and cross-compilation system. Comptime works without an OS.
Zig doesn't stop you shooting yourself in the foot. It hands you the gun with the safety on and a note explaining which end is dangerous.
Trade-off: Language still pre-1.0. API stability not guaranteed.
Odin — "The joy of programming, distilled"
Characterisation: C for people who ship video games
Axiom: "Memory is bytes; pointers alias; but the defaults should be sensible"
What it really is: Modernised C for large codebases.
Odin's freestanding target is first-class. The context system — Odin's mechanism for threading allocators and loggers through call stacks — works freestanding. Memory management is explicit.
Odin is what happens when someone who actually ships software designs a language, rather than someone who writes papers about shipping software.
Trade-off: Smaller ecosystem. Less tooling than Rust or Zig.
Hare — "Stability is a feature"
Characterisation: C if Dennis Ritchie had a time machine
Axiom: "Memory is bytes; pointers alias; but the language should be finished"
What it really is: What C might have been with hindsight.
Hare does not link to libc by default. It is designed explicitly for kernels, compilers, and system tools. The language specification will freeze at 1.0.
Hare's radical proposition: what if a programming language stopped changing?
Trade-off: Very early ecosystem. The project explicitly states support for Linux and FreeBSD only, on x86_64, aarch64, and riscv64 architectures. There is no intention to support proprietary platforms — this is a stated design choice, not an oversight.
C3 — "Evolution, not revolution"
Characterisation: C with a sensible haircut
Axiom: "Memory is bytes; pointers alias; but the syntax shouldn't fight you"
What it really is: C with obvious mistakes fixed.
C3 has full C ABI compatibility. You can mix C and C3 files in the same build with no friction. Contracts and slices work without libc. The compiler uses an LLVM backend.
C3 asks: what if we just... fixed the preprocessor and added slices? Sometimes the boring answer is correct.
Trade-off: Small community. Limited tooling. Pre-1.0.
Summary: The filter results
| Language | Tier | C-ness | Outcome |
|---|---|---|---|
| C | Baseline | ⭐⭐⭐⭐⭐ | The thing we're trying to replace |
| Rust | 1 | ☆☆☆☆☆ | Clear pass |
| Zig | 1 | ⭐⭐⭐⭐☆ | Clear pass |
| Odin | 1 | ⭐⭐⭐⭐☆ | Clear pass |
| Hare | 1 | ⭐⭐⭐⭐☆ | Clear pass |
| C3 | 1 | ⭐⭐⭐⭐☆ | Clear pass |
| D | 2 | ⭐⭐☆☆☆ | Conditional pass (-betterC) |
| Nim | 2 | ⭐⭐☆☆☆ | Conditional pass (manual configuration) |
| V | 2 | ⭐⭐☆☆☆ | Conditional pass (-gc none) |
| Swift | 2 | ⭐☆☆☆☆ | Conditional pass (Embedded Swift) |
| C++ | 3 | ⭐⭐⭐⭐☆ | Clear fail: companion to C, not successor |
| Go | 3 | ☆☆☆☆☆ | Clear fail: mandatory GC/runtime |
| Carbon | 3 | ⭐⭐⭐⭐☆ | Clear fail: wrong target (C++ successor) |
| Jai | 3 | ⭐⭐⭐⭐☆ | Clear fail: cannot evaluate (not released) |
Important distinction: The C-ness column measures semantic similarity to C's execution model. The tier column measures practical capability to occupy C's substrate role. These are independent axes. Rust scores zero on C-ness but passes all five substrate filters — it can replace C despite being nothing like it. Zig, Odin, Hare and C3 score high on both: they can replace C and feel familiar to C programmers.
Why the clear passes form the real contender set
The distinction between Tier 1 and Tier 2 matters.
Tier 1 (Clear Pass) languages (Rust, Zig, Odin, Hare, C3) are designed such that their distinctive features remain available in freestanding mode.
- Rust's borrow checker works without std
- Zig's comptime works without an OS
- Odin's context system works freestanding
- Hare's tagged unions work in kernels
- C3's contracts and slices work without libc
Tier 2 (Conditional Pass) languages (D, Nim, Swift, V) can target C's substrate position, but doing so requires abandoning the features that differentiate them from C.
- D without GC is just C with nicer syntax
- Nim without its runtime is just a C code generator
- Swift without reflection is just... less Swift
- V without autofree is still figuring out what it is
This is the meaningful distinction:
Which languages let you be productive in their idiom while targeting the substrate?
What each Tier 1 language is actually trying to fix about C
| Language | Philosophy | C's failure it targets | Approach |
|---|---|---|---|
| Rust | "Make invalid states unrepresentable" | Memory safety | Compile-time ownership tracking |
| Zig | "No hidden control flow" | Implicit behaviour, toolchain complexity | Explicit allocators, drop-in C compiler |
| Odin | "The joy of programming" | Ergonomic scaling | Context system, better defaults |
| Hare | "Stability is a feature" | Undefined behaviour, language drift | Conservative redesign, frozen specification |
| C3 | "Evolution, not revolution" | Preprocessor, weak type safety | Semantic macros, contracts, slices |
This explains why they coexist: they disagree on what's wrong with C.
The real fault line
The true divide is not syntax. It is this:
| Who controls memory? | Languages |
|---|---|
| Programmer | C, C++, Zig, Odin, Hare, C3, Carbon, Jai |
| Shared: Runtime + programmer | D, Nim, V, Swift |
| Compiler | Rust |
| Runtime | Go |
Rust is the only language where the compiler enforces memory correctness for safe code.
Everyone else either:
- Trusts you (Unmanaged) — "Here's a gun, try not to shoot your foot"
- Hides memory from you (Managed) — "What gun? There is no gun"
- Does both depending on mode (Hybrid) — "Here's a gun, but we've hidden most of the bullets"
Rust says: "You can have the gun, but I'm going to check your paperwork first, and also during, and also after."
The philosophical spectrum
The five Tier 1 contenders can be placed on two axes.
Axis 1: Compiler protection — how much should the compiler constrain you?
Maximum protection Minimum protection
| |
Rust -------- C3 -------- Odin -------- Hare -------- Zig
Axis 2: Language complexity — how much machinery does the language have?
High complexity Low complexity
| |
Rust -------- Zig -------- C3 -------- Odin -------- Hare
The philosophies track these positions:
| Language | Philosophy | Protection | Complexity | Personality |
|---|---|---|---|---|
| Rust | "Make invalid states unrepresentable" | Maximum | High | The perfectionist who won't ship until it's right |
| Zig | "No hidden control flow" | Minimum | Medium | The pragmatist who reads the assembly output |
| Odin | "The joy of programming" | Medium | Low | The game dev who's sick of fighting the language |
| Hare | "Stability is a feature" | Low | Minimal | The greybeard who remembers when C was new |
| C3 | "Evolution, not revolution" | Medium | Low | The conservative who just wants C, but less annoying |
The ecosystem reality
| Language | Philosophy | Can replace C | Is replacing C | Where |
|---|---|---|---|---|
| Rust | "Make invalid states unrepresentable" | Yes | Yes | Linux kernel, Android, Windows components |
| Zig | "No hidden control flow" | Yes | Yes | Build toolchains, Bun runtime |
| Odin | "The joy of programming" | Yes | Partially | Game engines, developer tools |
| Hare | "Stability is a feature" | Yes | Not yet | Too early (released 2022) |
| C3 | "Evolution, not revolution" | Yes | Not yet | Too early, small community |
C does not get replaced in theory. It gets replaced by where people migrate their code.
The real trajectory
C will not be "killed".
It will be:
- Surrounded — Rust in Linux, Zig in toolchains
- Absorbed — C3's C-mixing model
- Constrained — new drivers in Rust, not C
- Replaced in layers — userspace first, then kernel modules, then core kernel
Rust, Zig and Odin are already doing this. Hare and C3 show what a clean C could have been.
Conclusion
The story is not "C vs new languages".
It is:
Which languages can occupy the deepest layer of computing — the one C has held since 1973?
Fourteen languages were evaluated. Four failed outright or couldn't be assessed. Four passed conditionally. Five passed cleanly. One is the baseline.
Each survivor has a philosophy and an axiom:
| Language | Philosophy | Axiom |
|---|---|---|
| C | "Trust the programmer" | Memory is bytes; pointers alias; mutation is unrestricted |
| Rust | "Make invalid states unrepresentable" | Memory is owned; aliasing is controlled; mutation is permissioned |
| Zig | "No hidden control flow" | Memory is bytes; pointers alias; but we will tell you when you mess up |
| Odin | "The joy of programming" | Memory is bytes; pointers alias; but the defaults should be sensible |
| Hare | "Stability is a feature" | Memory is bytes; pointers alias; but the language should be finished |
| C3 | "Evolution, not revolution" | Memory is bytes; pointers alias; but the syntax shouldn't fight you |
The substrate is diversifying. Slowly, but measurably.
And the key insight:
Rust belongs to the C family only in grammar.
Zig, Odin, Hare and C3 belong to it in physics.
That is why Rust feels alien to C programmers, and Zig feels familiar.
They solve different problems.
Appendix A: Filter application detail
| Language | Freestanding | Deterministic layout | C interop | No mandatory runtime | Toolchain visibility |
|---|---|---|---|---|---|
| C | ✓ | ✓ | ✓ | ✓ | ✓ |
| C++ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Rust | ✓ (no_std) | ✓ (repr(C)) | ✓ | ✓ | ✓ |
| Zig | ✓ | ✓ | ✓ | ✓ | ✓ |
| Odin | ✓ | ✓ | ✓ | ✓ | ✓ |
| Hare | ✓ | ✓ | ✓ | ✓ | Partial (QBE backend) |
| C3 | ✓ | ✓ | ✓ | ✓ | ✓ (LLVM) |
| D | ✓ (-betterC) | ✓ | ✓ | ✓ (-betterC) | ✓ |
| Nim | ✓ (manual) | Via C | Via C | ✓ (manual) | Via C |
| V | ✓ (-gc none) | Via C | Via C | ✓ (-gc none) | Via C |
| Swift | ✓ (Embedded) | Partial | Partial | ✓ (Embedded) | Partial |
| Go | ✗ | ✗ | Partial (cgo) | ✗ | ✓ |
| Carbon | ✗ | ✓ | C++ focus | ✗ | ✓ |
| Jai | ? | ? | ? | ? | ? |
Appendix B: Complete language characterisation
| Language | Philosophy | Characterisation | Semantic family | What it really is |
|---|---|---|---|---|
| C | "Trust the programmer" | The dangerous uncle who owns the house | Unmanaged | The alias-centric memory model |
| C++ | "Zero-cost abstractions" | C's midlife crisis | Unmanaged | C with objects, templates, and regrets |
| Rust | "Make invalid states unrepresentable" | Your compiler's disappointed parent | Verified | A safe systems language wearing C syntax |
| Zig | "No hidden control flow" | C's responsible older brother | Unmanaged | C with a compiler that cares |
| Odin | "The joy of programming" | C for people who ship video games | Unmanaged | Modernised C for large codebases |
| Hare | "Stability is a feature" | C if Ritchie had a time machine | Unmanaged | What C might have been with hindsight |
| C3 | "Evolution, not revolution" | C with a sensible haircut | Unmanaged | C with obvious mistakes fixed |
| D | "C++ without the baggage" | The language that tried to please everyone | Hybrid | C++ plus garbage collection |
| Nim | "Write like Python, run like C" | Python wearing a C costume | Hybrid | Python syntax on a C backend |
| V | "Simple, fast, done" | The language of bold promises | Hybrid | Fast-compile application language |
| Swift | "Safety without sacrifice" | Objective-C's attractive replacement | Hybrid | Apple's managed systems language |
| Go | "Simplicity scales" | Java in a hoodie | Managed | Systems infrastructure language, not substrate language |
| Carbon | "C++ migration path" | Google's C++ apology letter | Unmanaged | C++ interop successor |
| Jai | "Game programmers know best" | The language equivalent of "coming soon" | Unmanaged | Unknown (not released) |
Appendix C: The four divergence paths from C
| Path | What they did | Languages | Summary |
|---|---|---|---|
| A: Keep C's physics | Kept pointer aliasing, manual lifetimes, UB | C++, Zig, Odin, Hare, C3, Carbon, Jai | "C, but we fixed the obvious stuff" |
| B: Hide C's physics | Replaced with GC, moving heaps, runtime checks | Go | "What if we just... didn't let you touch memory?" |
| C: Half-escape | Raw pointers when asked, GC when not | D, Nim, V, Swift | "Have it both ways (and debug both sets of bugs)" |
| D: Replace the model | Static aliasing constraints, compiler verification | Rust | "What if the compiler was your mum?" |
Appendix D: Freestanding substrate vs systems infrastructure
Freestanding substrate programming:
- You control the machine
- No runtime beneath you
- You handle interrupts, memory maps, hardware registers
- Examples: kernels, drivers, firmware, bootloaders, language runtimes
Systems infrastructure programming:
- You build infrastructure software
- Runtime handles memory, scheduling, I/O
- You handle requests, processes, orchestration
- Examples: containers, networking tools, build systems, CLI utilities
Architectural compatibility with hard real-time / ISR constraints:
| Language | Compatible? | Notes |
|---|---|---|
| C | Yes | Reference implementation |
| C++ | Yes | With care (no exceptions in ISR) |
| Rust | Yes | no_std mode |
| Zig | Yes | No runtime by default |
| Odin | Yes | Freestanding target |
| Hare | Yes | No libc by default |
| C3 | Yes | LLVM freestanding |
| D (-betterC) | Likely | Requires restricted mode |
| Nim (freestanding) | Unclear | Depends on stub implementation |
| V (-gc none) | Unclear | Pre-1.0, limited evidence |
| Swift (Embedded) | Unclear | Experimental mode |
| Go | No | Mandatory GC/runtime |
| Carbon | Unclear | Not yet positioned for this |
| Jai | Unclear | Not released |
Go is excellent at systems infrastructure. It is structurally incapable of freestanding substrate work.
Last updated: January 2026.
Top comments (0)