Essay
Is the Programming Language Irrelevant in the AI Era?
Java, the four walls, and why language-as-verification-contract is a promotion
I was a Java developer for years, and I loved the language. I want to say that plainly before anything else, because the rest of this post is going to sound like a breakup letter, and breakup letters are only honest when they start with what was good. Java was good. The syntax stays out of your way, the tooling is superb, and for two decades it let me build systems that made money and mostly didn't fall over.
Then I started chasing the last drop of performance from the machine, and my favorite language became my enemy.
The three walls
The first wall was the JNI tax. When you live at the bottom of the latency curve, sooner or later you need something the JVM doesn't give you — a syscall, an mmap'd region, an atomic with exactly the ordering you want. Java's answer is JNI, and JNI's answer is a toll booth at the border: marshaling, pinning, transition bookkeeping. Newer downcall machinery narrows the toll; it doesn't abolish the booth, because the platform's whole design assumes the crossing between "managed" and "native" is rare and coarse. For my call patterns it was neither. The boundary sat on the hot path, crossed millions of times a second, and its fixed transition cost was part of every crossing.
The second wall was the threads I never asked for. My system was single-threaded by design — one hot loop, one core, pinned and isolated. The JVM's opinion of my design was: here are a dozen housekeeping threads anyway. GC workers, JIT compiler threads, the reference handler, the finalizer, assorted VM internals. You can tune them, shrink them, sometimes starve them — you cannot remove them. And every one of them was another scheduler interaction whose timing I did not control, waiting to preempt the one thread I cared about — and at the bottom of the latency curve, the worst occurrence matters far more than the average one.
The third wall was warmup. There is no quick way to warm up a JVM, and — worse — no reliable way to stay warm. Tiered compilation gets you fast code eventually, on its schedule, after enough profile has accumulated. Then one unlucky branch, one new call-site shape, and the JIT deoptimizes you back to the interpreter in the middle of the trading day. The machine code executing your method is not a fact; it's a mood. I have spent real engineering-weeks building warmup harnesses that replay synthetic load to coax the JIT into compiling the right things — infrastructure whose entire job is to negotiate with my own runtime.
Each wall has the same shape: the platform inserts behavior between your source and the machine, and that behavior is not yours to remove. GC pauses you didn't schedule, threads you didn't spawn, machine code that changes underneath a method you didn't touch. For most software this is a fantastic bargain. At the bottom of the latency curve it's a landlord who keeps redecorating your apartment while you sleep.
The fourth wall
Here's the part I didn't expect: the AI hit the same walls I did.
When I started working with coding agents seriously, I noticed they were brilliant at writing Java and strangely bad at optimizing it. It took me longer than I'd like to admit to see why. An agent works in a loop: change something, measure, reason about the delta, repeat. That loop assumes the target holds still. On the JVM, the target never holds still. Run the benchmark twice and the JIT compiles differently, the GC fires at a different moment, a housekeeping thread steals a different microsecond. The agent sees noise, invents a theory about the noise, "fixes" it, and the fix changes nothing — or changes something else, which spawns a new theory. I watched an agent chase a phantom regression through three refactors when the actual variable was compilation tier. It wasn't stupid. It was doing sound inference on unsound data.
Humans hit this too — we just have years of scar tissue that tells us when to distrust a number. The agent has no scar tissue. A moving target doesn't slow AI down; it actively confuses it, because the agent's core competence is drawing conclusions from evidence, and the platform is manufacturing false evidence.
That reframed everything for me. The features I wanted to remove for latency reasons and the features that were confusing my agents were the same features. Nondeterministic scheduling, profile-dependent codegen, allocation with invisible deferred cost — every one of them widens the gap between what the code says and what the machine does. Humans pay that gap in debugging time. Agents pay it in corrupted reasoning.
Subtraction, again
So I built SuperJ: Java's syntax, compiled ahead-of-time to native code. No JVM, no JIT, no GC, no threads. I've written elsewhere about the design philosophy — reads like Java, behaves like C — but there's a point I want to make sharper here, because people keep getting it politely wrong.
When people hear a young language dropped threads, reflection, lambdas, and autoboxing, they assume the features were cut because implementing them is hard. Some of them are hard. That is not why they're gone. Every feature SuperJ removed was removed because removing it was the right call, and the walls above are the proof:
- No threads means no memory model, no fences you didn't write, and no housekeeping preemption — wall two, gone by construction.
- No JIT means the machine code is decided at build time and never changes again — wall three isn't solved, it's unaskable. A SuperJ binary's first request runs the same instructions as its millionth. The hardware and the OS still have their moods — caches, interrupts, scheduling — but the language runtime never rewrites the experiment underneath you.
- Natives are direct calls into C with no marshaling layer, because the memory layout is fixed and knowable — wall one, gone.
- No GC, no reflection, no dynamic loading: nothing in the runtime has an opinion, an agenda, or a background job.
And the fourth wall fell with the other three. Determinism turned out to be the single biggest gift I could give my AI collaborators. I should be precise about which determinism I mean, because the word covers too much: not a promise that every run costs the same nanoseconds — caches, interrupts, and the OS scheduler still exist — but the removal of runtime-generated code, hidden concurrency, and deferred memory work. What that buys an agent is a stable experimental surface: control or journal the external inputs, and a failure becomes reproducible instead of probabilistic. In SuperJ's own codebase the test suite is golden-output tests: compile the program, run it, diff stdout against a checked-in file. That style of testing is only possible on such a surface — same program, same inputs, same bytes out, every run. When an agent here changes the compiler and a golden test fails, the diff is signal — not a flaky thread interleaving, not a GC hiccup, not a warmup artifact. The agent's evidence is trustworthy, so its reasoning converges instead of wandering. I've watched agents in this codebase debug miscompiles down through LLVM IR to a single wrong instruction, unassisted. They can do that because nothing lies to them.
Watching that work is what pushed me from a practical observation to a philosophical one.
So — is language irrelevant now?
There's a fashionable argument that goes: if humans write English and the AI writes the code, the programming language is just an intermediate representation nobody reads. Pick anything. Syntax debates, expressiveness debates, language wars — all obsolete, all optimizing for human fingers and human working memory, both of which are leaving the loop.
Half of that is true, and it's the boring half. What's dying is language-as-human-ergonomics. What's ascending is language-as-verification-contract — and that's a promotion, not a retirement.
Here is the core of it: an LLM is a probabilistic generator, so the value of the whole system collapses onto whatever deterministic layer checks its output. English cannot be that layer; ambiguity is what English is for. The prompt is not the artifact of record. The programming language is where the AI's interpretation of your intent stops being vibes and becomes an exact, executable commitment. It may still be the wrong interpretation — but now it is something that can be inspected, tested, rejected, compared against a spec. Remove the human author and the language stops being a writing instrument and becomes the contract between intent and execution. That is a more important job than the one it had before.
Once you see languages as verification contracts, the design criteria reshuffle in ways this project stumbled into honestly:
The diagnostics channel becomes a public API. SuperJ's compiler errors carry stable codes — error[E_BOXED_PRIMITIVE]: ... — and the contributor docs say outright: branch on the code, never on the message prose, because prose may improve but codes are never renamed. That is error output designed as a wire protocol for agent loops. Twenty years ago error messages were UX for humans. Now they're part of the language's ABI.
Syntax still matters — but to the model, not the human. SuperJ looks like Java, and in the AI era that's not nostalgia, it's engineering: Java is one of the most heavily represented languages in every model's training corpus. The "syntax doesn't matter" crowd is right that humans stopped caring — and wrong about models, for whom familiar syntax means stronger priors and fewer generation errors. Syntax stopped being ergonomics and became a compatibility layer with the training distribution. "Java's syntax, none of Java's runtime" is almost the definitional AI-era language: maximize model fluency on the surface, replace the semantics underneath with ones you can verify.
But familiarity is a loan, not a gift. Java-shaped syntax also transfers priors that are wrong wherever SuperJ intentionally diverges — an agent will confidently reach for a thread, a lambda, an autoboxed Integer that doesn't exist here. That's why the semantic boundary has to be unusually explicit, and why the stable error codes above are not a nicety: familiarity gets the agent to a candidate quickly; the diagnostics keep familiarity from hardening into false confidence.
Semantics that agents can check beat semantics that humans can admire. Single-threaded execution, AOT compilation, arena memory, deterministic replay — every one of these trades away a convenience to make behavior reproducible and checkable. Verification, not generation, is the scarce resource in AI-built software. A language that gives agents a stable experimental surface is a language where their work can be checked cheaply — and where their own reasoning stays sound, because their evidence is real.
And the language doesn't do this alone. The source language by itself is not what makes agents effective. The working unit is the language plus everything bolted to it: the compiler's restrictions, the stable diagnostic codes, the agent-facing documentation, the golden oracles and unit gates, the replay journals. There is a word for that assembly: a harness. The programming language is no longer merely the target the coding agent emits; together with its compiler, diagnostics, tests, and runtime constraints, it is the harness within which the agent is allowed to act. "Language as verification contract" is the principle; the harness is the machine built out of it.
And the economics flipped. Building a language used to mean a platform company and a decade; AI has cut the cost of a working compiler, SDK, and toolchain by an order of magnitude. If languages were becoming irrelevant, that cost collapse would produce nothing. Instead it's producing languages. The future isn't one universal language or no language; it's more languages, each an opinionated contract for its niche, because the cost of minting a new contract just fell through the floor. One honest qualifier: AI has collapsed the cost of minting a language — not yet the cost of earning trust in one. Semantic stability, portability, an ecosystem, years of not breaking people: those still cost what they always cost.
The honest coda
Is language irrelevant in the AI era? It's the same question as "is mathematical notation irrelevant now that we have calculators?" The notation-as-handwriting part — sure, let it go. The notation-as-precision part becomes the entire game.
I didn't set out to build an AI-era language. I set out to stop paying the JNI tax, to kill the threads I never spawned, to run the same machine code at nanosecond one and nanosecond one billion. But every wall I tore down for latency turned out to be a wall between my agents and sound reasoning, and I no longer believe that's a coincidence. Predictability for the human reading the code and determinism for the agent verifying it are the same property. Java stopped giving me either. So I built a language that gives me both, and my strange new colleagues — who never loved Java, who never loved anything — do their best work inside it.
The one question I can't close: does reading survive — and at which layer? Everything above assumes a human still opens the file sometimes. Maybe that stops. Maybe humans eventually read only the layers above the implementation — specifications, capabilities, invariants, failure traces — while agents own the source below, and source languages drift toward compressed, machine-optimal forms. But notice what survives even in that future: there must remain some layer at which a human can understand, contest, and accept responsibility for what the machine does. Language doesn't disappear in that world; it moves upward, to the lowest layer where human judgment still lives. I doubt we get there soon — when things truly break, someone still has to look. But that's the fault line, and I'd rather name it than pretend it isn't there.