← SuperJ Manual

Memory Safety & Security: A Note

Why SuperJ doesn't have a borrow checker, and why that's the right tradeoff for most software.

The short version

Rust's borrow checker makes one class of bug impossible — memory safety bugs (use-after-free, double-free, buffer overflow, data race) — and charges a permanent per-line tax to get it: every lifetime annotation, every borrow-graph fight, every Rc<RefCell<>> you reach for when the checker can't prove what's obviously fine, paid on the first write and on every subsequent edit, by every engineer, for the life of the project. That tax compounds — it slows onboarding, slows iteration, turns small refactors into borrow archaeology, and pushes people to avoid changes they'd otherwise make.

SuperJ charges none of that tax. You write Java. In exchange, memory bugs are possible — they crash at runtime instead of being rejected at compile time. The question is whether one bug class being impossible is worth a permanent tax on everything you ever write.

The answer, for most software: no

The bug class the borrow checker eliminates — memory corruption as a route to code execution — is a serious one, but it is a narrow one. It is the class that drove two decades of browser and kernel security patches, and for that exact software it is worth the tax:

This is the list of software where one memory bug is catastrophic and the bug surface is unbounded. It is a real list. It is also a small fraction of what gets written.

For everything else — servers, services, API backends, data pipelines, network daemons, the actual bulk of production software — the threat model is not "attacker gets code execution via memory corruption." It is "the logic returns the wrong answer" or "the service crashes under load." Memory safety is irrelevant to both. The CVE databases skew toward memory bugs only because memory bugs are the ones that get assigned CVE numbers; logic bugs cause incidents that never get filed as vulnerabilities. If you weight by bugs that actually hurt users in production, logic bugs dominate, and the borrow checker does nothing about them.

What SuperJ gives you instead: determinism

This is the other half of the trade, and it is the half the standard framing leaves out. SuperJ's single-threaded + SEDA model gives you determinism: the same event sequence produces the same state, bit-for-bit. That buys you a property no memory-safe concurrent system provides:

The sharp version: **memory safety is a negative property ("this bug class cannot happen") obtained by introducing nondeterminism, which is a positive source of insecurity ("behavior now depends on things an attacker can influence").** The borrow checker removes one failure mode and the concurrency model opens a different, larger one. Determinism closes the second by construction, and makes the first reproducible and fixable.

The economic comparison

RustSuperJ
Per-line costHigh, permanent, paid on every editLow — Java ergonomics
What it guaranteesOne bug class impossible (memory)One property present (determinism)
What it doesn't helpLogic bugs, deadlocks, the other ~90%Memory bugs (until you fix them, which you can)
Convergence model"It compiles, therefore no memory bugs" (silent on everything else)"It reproduces, therefore you can fix any bug"

The asymmetry is the point. Rust spends enormous effort eliminating a minority failure mode and introduces nondeterminism that makes the majority failure mode harder to fix. SuperJ spends no effort on the minority mode and gives you a workflow that makes the majority mode tractable.

When to reach for which

The reason the industry treats memory safety as universally worth it is that "memory safety" sounds like an obvious good and "ergonomic cost" sounds like a complaint — when in fact the first is a narrow guarantee and the second is a pervasive tax. You pay a lot for a little, in most cases. SuperJ's thesis is that the one class of bug Rust makes impossible is not worth the cost of making it impossible, for most software — and determinism, which costs almost nothing, gives you a workflow that fixes everything else.

The ideal (and why nobody ships it)

Single-threaded Rust has both properties: the borrow checker's memory safety with no concurrency-induced nondeterminism. That is strictly better than either pure option. It is also the configuration nobody talks about, because it defeats the marketing — "fearless concurrency" loses its point if you don't use the concurrency. SuperJ's bet is that for most software you don't need the concurrency, and giving up the memory safety to get the ergonomics is the better trade than giving up the ergonomics to keep a guarantee that only matters for a threat model you don't have.

SuperJ — manual · generated from memory-safety.md at pack time