The Age-old Resistance to Generated Code

Sep 16, 2023

“AI-generated code is making me a worse developer.”

“GitHub Copilot code is riddled with bugs.”

“Generated code is way less efficient than something I wrote myself.”

Developers are right. AI-generated code isn’t as good as something you or I could write. It has bugs, often hard to find because we are giving up some of our control. Even if it’s the correct implementation, it’s one of the slower implementations. But it’s important to remember: these were the same arguments made in the 1950s through 1970s about compilers vs. assemblers.

Compilers took up more space, produced less efficient code, and added a layer of misdirection between programmers and the machine code. They weren’t seen as serious tools for developers. Ironically, it limited the types of hardware to which you could deploy your software — not all machines had the space or memory for a compiler.

Grace Hopper wrote one of the first compilers, “A-0,” on UNIVAC in 1952 (today, it would be considered a linker rather than a compiler). But Hopper was one of the loudest advocates for high-level (i.e., not assembly) programming, primarily via languages like COBOL. Developers (and academics) thought COBOL wasn’t a serious language because it was closer to English than machine code (how far we’ve come).

When FORTRAN was released, there was intense skepticism about the usefulness of high-level languages because of inefficient transforms. John Backus and his team worked hard on optimizations so that the FORTRAN compiled code would be faster than the average developer. His work paid off: the FORTRAN compiler found commercial success because of this selling point.

Unix was originally written in assembly language. In 1973, Unix Version 4 was rewritten in C. This was controversial. Most operating system kernels were written in assembly for performance. Writing in a high-level language was instrumental to Unix’s success (portability, developer velocity, readability, etc.)

Even in the 1980s, applications like Lotus 1-2-3 were written in assembly for performance and targeted specific hardware, like the IBM PC. Assembly was still seen as the go-to layer for performance-critical code.

Today, high-level (this time, meaning no manual memory management or GC) code still gets a bad rap. Terminals, frontend bundlers, and more are getting rewritten in Rust. Developers are right — code written in Rust, Zig, or another performance-focused language is usually much faster than programs written in (something like) JavaScript.

Five years from now, we might not care. We might have LLMs automatically rewrite the performance-critical sections of our code in lower-level language. We might even have LLMs identify our code's performance-critical sections. It’s a delicate balance between creating higher-level abstractions so developers can focus more on the logic and creating escape hatches to go one level deeper.