C Is Back
High-level languages traded machine time for human time; coding agents change the price
For forty years, the history of programming languages has mostly been a history of spending machine time to save human time. Garbage collection, dynamic typing, rich standard libraries, virtual machines, layers of frameworks: each one made programs easier to write and a little slower to run. Python won the decade on exactly that bargain. C, which gives you the hardware and very little else, kept the kernels and the databases and lost most of the rest.
That bargain was right for its time. I think its time is ending. When an agent writes the code, the human cost that high-level languages were built to save mostly disappears, and the machine cost they charge does not. C is back, or at least the case for it is.
Every abstraction was a trade
Languages did not grow complicated by accident. Each convenience removes a burden from the programmer and moves it into the runtime. A garbage collector means you never decide when memory dies; the runtime decides, later, and pauses to do it. A generic container means you never write a hash table; you pay for indirection on every lookup. A virtual machine means you never think about the processor; a JIT thinks about it at run time, after a warm-up you wait through.
Put differently, high-level languages postpone decisions. They let the programmer leave memory layout, lifetimes, and types unstated, and they bind those decisions at run time instead (see Every Decision Has a Binding Time). Postponing costs cycles, but writing every decision down costs people, and people were the scarce resource. C is the opposite design: simple, close to the hardware, every decision made explicitly by whoever writes the code. Dangerous, and blazingly fast.
Writing it down is cheap now
Coding agents change both terms of that trade. The boilerplate that made C tedious, hash maps, growable arrays, manual memory management, costs an agent seconds. It does not need abstractions to keep a large program in its head. So the main reason to postpone decisions is gone; you can afford to bind them early again.
The other cost of C was bugs, and here I want to be precise. Agents still write bugs, including the memory bugs C is famous for. What changed is that an agent also runs, without complaint and without being reminded, the tools that catch them: AddressSanitizer, UndefinedBehaviorSanitizer, differential fuzzers, brute-force oracles. Humans knew those tools existed and mostly skipped them, because they were slow and boring to set up. The danger in C was never only that bugs were easy to write. It was that checking was expensive, and nobody did enough of it.
An experiment: Boomslang in C
To test this, I asked a coding agent to port one of my research systems. Boomslang checks whether a database honored the isolation level it promised. It reads a trace of what clients sent and received and searches for an ordering of transactions that explains it. The problem is NP-complete in general, so the checker is really a small compiler: parse traces in eight formats, build a graph of what is known and what is uncertain, prune it, and hand the rest to a SAT solver with a graph-acyclicity theory. Its published artifact is about 24,000 lines of Java, plus MonoSAT, a 98,000-line C++ solver, called through JNI.
The port took two prompts: “Implement Boomslang in C language,” and a loop telling the agent to keep going until the C version ran the same tests as the Java one. Twenty-two hours later, with no message from me in between, it did. A few days of short follow-up prompts later, the numbers on the artifact’s own experiments were these:
- 60× faster (geometric mean over 78 runs where both finish) and 48× less memory. On TPC-C with 50,000 transactions, Java takes 173 seconds and 62 GB; C takes 1.2 seconds and 0.63 GB.
- 4,900 lines of C at the first complete commit, against 23,900 lines of Java and the 98,000-line solver. No dependencies beyond libc and pthreads.
- The same verdicts as Java on all but one run.
The full account, with every prompt, is in the porting notes.
Where the speed came from
A port that changes the language and the algorithms at once makes it hard to credit either, so the C version has a flag that builds exactly the graph Java builds. With the same graph, C is about 30× faster. That is the language: no JVM start-up, no garbage collector, no JNI boundary, data laid out the way the algorithm reads it. The remaining 2× (4.5× on large runs) came from algorithmic changes the agent tried once it had a fast base and a reference to compare against, such as a reachability structure whose memory grows with transactions times sessions rather than with transactions squared.
The solver is the more interesting number. MonoSAT is a general SMT solver with many graph theories. Boomslang needs exactly one, acyclicity. The agent wrote a solver for that one theory: 887 lines. General-purpose libraries exist largely because writing the specialized version was too expensive for a person. When it is not, you write the 887 lines that do only what you need.
The precondition is a judge
None of this would mean much if the C code could not be trusted, and this is the part I find most important. Every claim of correctness rested on a comparison with something independent: the Java artifact on thousands of random traces, a brute-force serializability oracle on 40,000 more, a literal reading of Adya’s thesis for every isolation level he defines. The agent built most of these judges itself, before it needed them.
The judges also found the agent’s own worst bug: a solver error present since the first commit, which never produced a wrong verdict in any test and surfaced a day later as a heap overflow under AddressSanitizer. That is exactly the bug C is feared for, and it was caught exactly the way C bugs should be caught.
The agent never had to be right on the first try. It had to be checkable.
What C still costs
Let me admit the parts I hold loosely. The same argument favors Rust, which catches at compile time what sanitizers catch at run time; “C is back” is partly a claim about low-level languages in general, and C is simply a representative case. The C solver is still slower than MonoSAT on one deliberately hard instance, because its branching heuristic is simpler.
So the remaining cost of C is review, and review is easier for 5,000 lines than for 24,000 lines plus a dependency.
Let me be accurate: what is back is not nostalgia for C. It is the old rule that the person who knows what the program needs should write it down, now that writing it down no longer costs a person.
References
- Jian Zhang, Shuai Mu, and Cheng Tan. Making Transaction Isolation Checking Practical. ACM ATC 2026.
- Atul Adya. Weak Consistency: A Generalized Theory and Optimistic Implementations for Distributed Transactions. PhD thesis, MIT, 1999.
- Sam Bayless, Noah Bayless, Holger H. Hoos, and Alan J. Hu. SAT Modulo Monotonic Theories. AAAI 2015.