The foolishness of "natural language programming" (1978)
cs.utexas.edu
cs.utexas.edu
Dijkstra's arguments tend not to change their minds. I think the analogy takes hold because there is a kernel of truth in it. AI models now give us the magical ability to program in natural language, but the implication that an AI model is a form of compiler is deeply flawed. AI models don't replace compilers, they replace software developers. The reason software developers rarely look at assembly code is that compilers (and emulators and VMs) are able to precisely preserve the semantics of the original program.
A natural language spec is not a program, and there are many possible programs that can meet the spec. Software engineers and AI models turn specs into code, but the code is not the spec I think the analogy clouds our thinking about the value of programming languages as a tool for formally describing what the computer should do and enforcing properties of the program that should not be left to either humans or AI models to uphold.
This stochastic nature existed before AI. Humans are stochastic too. Two engineers convert specs to code in two different ways. I would argue the distribution is wider among humans than among agents.
I would argue that, in the absence of such evidence, we cannot conclude that the English-to-code conversion process is stochastic; it is merely not deterministic, which is altogether different.
Well, then, their interpretations of the spec are stochastic. Good enough for me, anyway.
while both LLMs and humans are not 100% deterministic, I don't think that's the interesting part. It's both true that there are many assembly language programs that implement a C program and that there are many valid programs (in any programming language) that correctly implement a natural language spec. But there's a significant qualitative difference between the two types of translation and that would be true regardless of whether the translations are stochastic.
It would be interesting to state sane measurments that determine a "distance" between a spec and software that claims to implement it
Please go ahead and do.
So? Two compilers convert source to binary in two different ways.
Even if we allow for hermetic builds in some cases in many many other cases your runtime will recompile your code based on its observations about your environment and that’s frequently what we want.
This fetishism of “determinism” seems crazy to anyone that has had to spend time really digging into modern JIT based compilation.
Copium.
So all of a sudden all focus is on the word "determinism", and before even going down this route you have to agree on what aspect of the subject are you declaring to be "deterministic?"
Its sort of like chatting with libertarians, as soon as you agree that taxation is theft and democracy is tyranny then all problems melt away!
Yup. Pure obfuscation.
The point is reliability.
What makes agents useful is not simply that they interpret natural language, it is that they are interactive and ambiguous instructions can be corrected when the agent's output is not what the programmer intended. That is not the same as writing out a spec and giving it to a developer to implement.
You can interact with AI and say "code me a calculator" or "now declare a array of booleans to map to each of the keys in the UI and set the corresponding array position to true when the key is pressed".
These commands are written in natural language at such different levels of abstraction that is hard to put them in the same bucket. It would be fair to call the latter an imperative language with the LLM in the role of a compiler. That's very similar to how I use AI.
That would just be the "I" part, since was missing the A for artificial: you asked a naturally made person.
And yes, nobody argued that they didn't have I in 1978, so I'm not sure what the argument is supposed to prove.
I’m guessing it’s supposed to show that if you have to have arbitrary levels of intelligence to interpret natural language, then nothing’s changed between now and 1978 when considering whether “natural language programming” is a thing. Just because the intelligence is artificial now doesn’t really change the answer.
Not only it changes the aswer, it's literally the whole of the question. When people talked of the posibility or imposibility of “natural language programming” they *always* meant "natural language instructions which *a machine* translates to running code".
They didn't have to spell it out, since nobody doubted a human programmer can write code when given natural language instructions - that was already a thing since ENIAC, if not since Ada Lovelace.
That's what we have now, and that's what changed between now and 1978 when considering whether “natural language programming” is a thing.
- You can program in natural language
- You can tell an AI what to do in natural language, and it can gather requirements, sketch up a design, write code, search the web for error messages, and iterate on the program until it works.
For certain things people care about, they’re equivalent (I tell the computer what I want and out pops a program) but for certain other things, they’re absolutely not (natural language doesn’t map deterministically into machine instructions.)
When people talked about natural language programming decades ago, they were talking about a system that compiles natural language into machine code. They weren’t talking about a system that autonomously gathers requirements, decides what frameworks to use, searches the web to look up error messages, iterates on ideas, etc… these things are so different from “natural language maps to machine code” that I don’t think we’re going to have a useful discussion if you think “I tell the computer what I want” is the only aspect of this worth looking at.
This confuses two things still:
People wanting to have natural language to machine code via AI, just AI that was implemented the way they thought was achievable then (symbolic AI).
People wanting to have natural language style programming language, similar to later AppleScript or some 4GL languages.
Natural language programming, or natural language processing, as it was called, was tied to the first, and the AI research of the time, from the beginning:
https://en.wikipedia.org/wiki/Natural_language_processing
So, yeah, they didn't have LLMs, but they pretty much understood such a program or "compiler" would need to understand world facts and natural language to even work.
NLP has nothing to do with programming. The Wikipedia article you linked doesn’t even mention programming once. NLP is old-school AI like you get when you try and cram all language into an ontology and try to “parse” it in an unambiguous way. It’s how Siri worked from the beginning, and it’s a complete dead-end. (I have some background here, I was an engineer on Siri for over 10 years.)
The fact that a compiler using old-school NLP would need a complete understanding of the world and all relevant facts in order to make natural language “process-able” is the reason the whole thing was a failure and why LLM’s are needed to make the idea work. You can’t just go from “parsing language” to “make me a TODO list app” without having an arbitrarily intelligent system to understand all the relevant background that such a statement implies.
When people realized human-level intelligence is necessary to make natural language programming work, is basically when the idea died. And now we have LLM’s and (what many would define as) human level intelligence, and its ability to program is just one side effect of many of it being truly artificially intelligent.
IME LLMs often make reasonable assumptions, but sometimes they don't and you have to backtrack and say "No, what I meant was..."
When the process works it's almost magical because the LLM successfully anticipates your needs, and implements your request in a much fuller way than you might have done yourself.
When it doesn't it makes a mess you have to clean up.
But generally I've been impressed by how well the leading LLMs will Do The Thing from a brief description, interpolating useful and correct details without being told to.
Compilers don't work like that. They're translators, not (entry level) inventors with independent agency.
There are a few little differences between human beings and computers that you should know about.
For example, humans are sentient, have agency and can be held accountable.
So when you give humans a bad spec, you can still get what you want, because, with some luck, you're simply delegating the task of thinking and making choices to another human, who, by the very premise, understands the language you are communicating in, and can work out your intents with you.
The whole "this meeting could've been an email" thing, you know.
That meeting could've been a pull request if whoever needed a thing to be done could figure it out on their own.
LLMs can be helpful for figuring things out, sure.
But "sudo make me a sandwich" style of vibe coding is just removing the obstacles to enshrining ambiguities and bad decisions in code.
I'm of the opinion that if you think it will stay this way you haven't been paying attention. "sudo find me a security flaw" already embarrasses top security researchers who have been working on the same code for decades. "sudo decompile this program/firmware/game" is doing absolute wondrous things right now even if there are still some flaws. If it can do these things better / significantly faster than humans already, and if it keeps improving at the rate it has been "sudo make me an operating system" that spits out something actually pretty good is probably within a decade.
The Kolmogorov complexity, at best, remains unchanged.
"sudo make an OS" is a different kind of transformation.
It's as much programming as downloading an Ubuntu image, and you don't need to wait a decade to do that.
No, the article explicitly says that the difference is formal vs informal language.
> Programming remained the use of a formal symbolism and, as such, continued to require the care and accuracy required before.
One can define an operational semantics for (at least a subset of) the programming language (even for sloppy one, since they are still very small and restricted). One can prove the semantics preservation theorem formally, or reason somewhat in a similar way informally.
With natural language you kinda lose it, and we don't even touch the fact that models are probabilistic.
And if the latter is guaranteed to be interpreted unambiguously...
...Congratulations!
You have invented a programming language!
But now, that requires 20x more typing and 1,000,000x more compute to compile to machine code.
Which is the point of the article.
In my opinion, LLMs don't challenge anything.
That's a funny euphemism for career change. I'll remember it.
If anything what agents will mean is a move toward compilers for languages with more expressive type systems that can do more static checks for semantic correctness e.g. F*, which is an extension of F# that introduces dependent types.
No, they replace the need for a precise description of what you want the computer to do by a mechanism that's really good to fill in the gaps. But guesswork only takes you so far.
Guess what wasn’t?
The nonfunctional requirements.
Also: my app needs to do LLM classification. But instead sometimes the coding assistant wrote not an LLM api call but it wrote a regex to classify instead. This was despite the fact that I mentioned to not use regexes to classify things with.
Non-technical people don’t know what a regex is. Usually they also aren’t knowledgeable enough about nonfunctional requirements.
All of this may improve over time of course. But right now, I am not impressed (in terms of replacing SWEs).
OK, so you test it, see which nonfunctional requirements it doesn't meet, and ask the AI to change the code to include them - repeat until you're happy.
I have plenty of those in decades of human programming too, so...
In general I got the feeling that AI saves a lot of work, avoids a lot of big category, but also introduces new but categories that you need to account for.
Personal example of what LLMs can't do, but I could: I made a script to update some version numbers in some files, based on some other files. Simple stuff, and one of my colleagues told me "ask the AI, it will take 5 minutes". Well, no, because the files sit on different machines, and extracting the files from one machine and putting the result on the other machine requires knowledge of the infrastructure. Again, simple stuff, but the AI doesn't know, and we certainly are not going to let it run wild in our network. I know all this because I talked to the team, attended meetings, and did a bit of careful exploration. I am trusted with resources to do my work in a way the AI doesn't, I am sure it is mostly because I can take the blame me if I misuse them.
Sure, but LLMs do ask some questions already, and there is no reason to think they can’t keep getting better at knowing the right questions to ask.
Humans also often fail to do this well, and I think we all have experience with developers who do a very poor job at understanding what is actually being asked of them.
Maybe LLMs will never become as good as an expert developer at being able to suss out what someone is actually trying to do when they make a request, but it is certain LLMs will become better at it, and there is no reason to currently believe they couldn’t eventually become as good as the best humans eventually.
And like with a team, many programs could meet what I asked for, but I check the behavior of what they built, not the code directly. I think of it as working on the level of an engineering director, who also doesn't review code directly. Each agent shows me its change running in the app, in a short narrated screen recording, like in a launch review for the director. When it's not what I meant, I say what, and it goes another round.
However you can't prevent some other people from working as software developers who write and read code.
Even with cars, you still walk. Even with factories, someone still craft handmade bags.
if (date == <some random future date>) { crash_and_burn_the_world() }
??
I actually found code exactly like that would break a test on a certain date, using an agent.
It's really good at flagging things like this, which tend to be leftovers from a human process that nobody has had the time to clean.
Could there be a less egregious version of that in the code? Sure, but then that's just a normal bug where implementation doesn't match intention, and that happens to human developers as well. I find that Opus 5.5 is so good that it writes pretty good code that follows YAGNI, KISS, DRY, and is fine with writing a lot of tests, so my sense is that the rate of normal bugs is actually lower than with human developers.
Now, if you're assuming malintent on the side of the model creators, well, that's another story. FWIW, in a commercial project, where I also work at the "engineering director level" since Opus 5.5, all non-trivial changes go through reviews by Codex and Grok (locally) and Greptile (on the PR), so there would have to be some serious level of collusion by the labs to produce your example ;)
You would be well served to review the code. I don't usually need to do much of that since I work with models edit by edit, with every single line they write approved by me.
You would be surprised at all the errors even Claude Opus 5.5 commits. Not syntax or even basic logic errors, but more insidious errors that betray a lack of being able to see the bigger picture, or serious architectural errors.
If you want example, I have them in abundance. These models still need serious supervision. Unless you are spot checking the code deeply, you won't notice.
How do I know? It several times present deep architectural decisions to me, where each options may seem plausibly good. I rely on my deep architectural knowledge and experience, and knowledge of my vision for the product to steer it to the right option.
I think "I'm working in a higher level of abstraction" is easier for some devs to say than "I asked somebody else to do the thinking and the work." I don't think there's anything wrong with asking an LLM to do the work. But pasting jira tickets into claude is not abstraction lmao.
I guess arguments on either side of this can get difficult for a reason that another commenter already mentioned: you can use LLMs on a wide spectrum of granularity. You can one-shot a whole project, or you can tell it to rename some vars in a single file. I guess there are uses that are probably closer to programming. But if you're not even looking at the code, I'd say that's closer to somebody else doing the work
What I want to preserve in the AI-code-gen age that I still can form a high-level "theory of the program" and be able to dive deep and understand parts of it, both with and without AI. I'm concerned that we're headed towards a world where it's not possible to understand or modify even the simplest programs without a swarm of agents that you direct with incantation.md files.
'Precisely' is doing a lot of work here. Depending on your language some things might be preserved and some not. Eg if you write stuff in Haskell, you don't really preserve much of anything about memory usage, you leave that to the runtime system to figure out, and exactly how the GC works isn't really specified in the language standard.
Of course, you can redefine what 'semantics' means to say it's the kind of stuff that should be preserved in a translation. But as I said, different languages care about specifying and preserving different things.
See also how most languages (or their specs) don't particularly care about letting the user specify exact timings of operations.
Maybe they trust the practical results they see over what a professor wrote 50 years ago as an essay.
I'm not saying it's all mathematical purity. Programming languages themselves have specs and sometimes they are ambiguous or allow undefined behavior. Compilers have bugs. But the gap between the source code and program behavior is typically extremely thin and language implementations work towards making it airtight.
There are differences and the article highlights some of them - but there are difference between programming in a functional language and an imperative one, there are differences between programming for a RISC machine and a CISC machine, there a lots of different semantics that programming languages support. Now we have a language with underspecified semantics.
No, what agents do is expand the scope of problems software developers can solve. It is no different than the introduction of compilers, type checkers, garbage collection, and so forth. A programmer in the 1950s could not have imagined how anyone could build a software system like Hacker News, let alone the complex software systems we basically take for granted in this century. It is hard to imagine what kind of software future generations will take for granted because of how much more power programmers will have with things like agents (and whatever comes next -- this is hardly the end of the story).
But I am going in an opposite direction. Instead of rejecting formal languages in favor of natural ones, I think we should embrace formalism even on the level of specifications, requirements and our model of the world. Partly because that's what LLMs actually do - they de facto formalize these things.
Some people will push back that agent development is "natural language programming" but I don't think that's right. I think in that case the agent is the one programming, and the programming still always happens in a deterministic language like Rust/Python/Typescript/etc. Maybe that'll change, but to me at least the other way would be a disaster.
The best exception I know of though, is definitely the Inform 7 language which is for writing text adventures[0]. It has a lot of fans, and I've never gone deep with it, but seems to do a pretty elegant job or marrying up natural language and programming together in a unique way.
Either way, definitely a must-check-out for any language-geeks interested in natural language programming.
Existence proof: everything Claude Code does, including talking to LLMs on GPUs via the Anthropic API, and shelling out to other tools installed on your system, could in principle be compiled into one big self-contained binary (or Turing Machine if you prefer) that is able to take natural language in and produce compiled binaries out.
If you wanted to go a bit harder you could train Claude to output machine code directly, but that's not necessary. Whether the machine code comes straight out of an LLM or out of a compiler that is fed source code that comes from an LLM is a mere implementation detail, there's not any fundamental difference.
There are also times when you want the final product to be able to target different architectures and platforms. Generating into a higher level language allows for re-targeting the code by only changing a few compiler & linker flags or runtime/environment config. I would much rather that than hoping the LLM is feature- (and bug-)compatible between generation runs.
On the other hand, there exist programming languages (like Jot, a certain encoding of combinatory logic) where every binary string is a valid program.
Yet the point about DSL is interesting, in particular internal/embedded DSLs [2]. I lied a little earlier, my third programming language was actually Forth. His creator said in 2001, "When you devised an application you wrote a hundred words [i.e. functions] or so that discussed the application and you used those hundred words to write a one line definition to solve the application" [3].
I've been trying to do that exactly that in other languages, make it so that the code expresses "naturally" what it does as much as possible. When you succeed, people call your code "beautiful" or "elegant" (nobody ever told me that :-) which, I think, subsumes "naturality".
This is of course harder to do in low-level languages such as the ones I mentioned (except Basic maybe) because you get caught in details such as memory management. But high-level languages are not exempt of these problems (and contrary to Forth or Lisp, their syntax is often written in stone). Then there's essential complexity [4], which can be "unnatural" no matter what, like thinking about things in a concurrent programming context, with languages that don't natively support it like they support automatic memory management (i.e. garbage collection).
The topic is dangerously close to "readability", which is known to be 80% subjective.
[1] https://www.cs.utexas.edu/~EWD/transcriptions/EWD08xx/EWD831...
[2] https://en.wikipedia.org/wiki/Domain-specific_language#Domai...
I am not sure we actually want natural language to be compiled directly to machine code anyway. Those rich type systems that Haskell people get excited about are actually automatic proof checkers, similar to Lean, and having an agent check its output against such type checkers greatly improves the code generated by agents. If anything, we will probably see more widespread use of the lambda cube type systems (with extensions e.g. double negative elimination) as agents become a standard programming tool; human beings tend to find such type systems very tedious and difficult to work with, but agents are good at dealing with tedious tasks.
As opposed to creating flows where LLMs do something on the fly.
Code creates determinism, LLMs don’t.
You should own and be the expert on the architecture and design of what you're building regardless of whether yourself, an LLM or another person is writing the code.
The LLM isn't "smarter" than you, it's more resourceful. It can (to varying degrees of success) translate your design into code. If you aren't still taking ownership and driving the design of that logic, the LLM isn't going to bring you success with anything other than single-use or hobby applications.
You can take any idea and try to flesh it out with pseudo code. Once that’s done, try to convert it to real code and you’ll see that process is fairly mechanical. This is why people says that coding wasn’t an issue for ages. Coming up with the algorithm is the hard part.
People that have an issue with coding either are not familiar with the language/platform or is trying to think with real code instead of pseudocode or diagrams.
ADDENDUM
There are techniques to think with real code, moslty the Edit-Compile-Run workflow coupled with a good editor, or the REPL workflow (also helped by a good editor). Then add a good integration with a documentation system (manual pages?) and you’re golden.
But I’ve been on projects where a dev cycle relies on a 20 minutes local rebuild or one hour CI run. So it can be very hard to try to apply those workflows to legacy projects.
Of course there are problems where knowing the code deeply is essential to solve the problem, but those really aren't the majority, if even less than 1% of business problems.
When it comes to what the average developer needs to understand, having a strong grasp on one functional and one procedural language can enable you to solve almost every problem in any language ecosystem, provided the correct resources. If you can do this, you can utilize an LLM for programming assistance well. If you can't, you probably should not heavily rely on one at all yet.
Critical thinking is essential for nailing down your essential complexity (the core solution of the problem). You can try to define invalid and edge cases alongside the happy path in the pseudo code diagrams version, even if it's a TODO comment.
This is what software engineers do but just more expensive and time consuming.
The lack of intelligence in the loop is the foolishness the title refers to.
The entire point of the article was that human language isn't suitable for instructing computers, and you somehow make the leap to "humans instructing humans must be the same thing".
Reading comprehension must be a thing of the past at this point.
Reading comprehension must be a thing of the past at this point.
I don't think I'd want to call it "natural language programming" in the way Dijstra's implying here unless the prompt was the thing that was actively being executed/ran/whatever when someone loads your app or website.
This works well in e2e type tests where the test implementation might change but the customer experience hasn't.
So maybe there is a hybrid approach in our future.
I think those are different from pure "natural langyage programming" though because there's normally code you've written that's calling out to the LLM, so it's within the context of written code.
I think this, and lots of other comments are so interesting. There are a lot of different increasingly complex ways LLM outputs and coding are being tied together by people, that I hadn't really considered.
Whether "natural-language-like syntax" is enough "count as natural language programming" is probably a question of definition. For Dijkstra's essay here, he doesn't offer a particular definition, but he certainly seems to be implying something much more fluid and ambiguous than Inform7 is.
I definitely didn't mean to imply Inform7 had achieved the holy-grail of natural language programming or anything.
I think Dijkra's main point he's driving at is here:
> I suspect that machines to be programmed in our native tongues —be it Dutch, English, American, French, German, or Swahili— are as damned difficult to make as they would be to use.
I'm inferring/assuming a bunch, but I think he's saying something along the lines of, programming is useful because it is precise, and natural language is not precise, so attempts to make programming languages more like natural language are butting up into this inherent contradiction of precision. And therefore will end up as worse programming languages (for attempting to be more naturalistic).
In the history of programming languages, I think most attempts to be "more natural language like", such as COBOL or AppleScript, do become worse for attempting to walk the tightrope between natural-language and programming. I think Inform7 is unusual in that it achieves that balance in a way that isn't just objectively terrible (you may disagree) - I think that's mostly because it offers very few programming constructs, and is a tool for writing a kind of prose (text adventure games).
Anyway, to come back around, that was my reasoning for mentioning Inform7 - I think it's an interesting deviation from other experiments in natural language programming so far.
But even if we write in Python like foo.bar(), the interpretation depends on what is in module foo and function bar, how they are defined contextually.
You can try to find some difference but most modern AI agents come more close to a language interpreter than not, if the actual instructions are given.
OTOH, giving instructions to people is not programming. People do not consist of binary code that is reliably executed; they are biological organisms subject to environmental pressures such as being tired. They have their own consciousness and will, and can refuse to follow the instructions. LLMs are programs; they cannot decide not to respond.
If you design a custom piece of furniture, then hire someone to build it, that's totally fine! But if you then tell everyone "I constructed this cool table," well, that's just not true.
This is the difference between "made in China" and "designed in California, assembled in China". People will generally not say "I constructed this table" just as an architect won't say "I built this house", unless you have the context that they're an architect or they're trying to mislead you.
There will come a time where by default we interpret "I built this software" not to mean that you literally wrote the code, unless you say that explicitly, just as when somebody says "I built this computer" we know it means they picked the parts, rather than soldered the boards, which is what it meant in Woz' day.
Anything can be anything it isn't once you start changing the language.
"When at first you don't succeed, redefine success."
> Having software build software is programming. An agent is software, a human isn't. I can draw a UML diagram, software generates code from that, and software turns it into binary.
It's not programming, it's cuckoldry. Articulating the perfect guy, inviting him over and watching him get to do all the stuff you used to enjoy literally makes you a manager.
Karpathy said it best. To paraphrase: there will be a rift of hate/love between programmers and builders respectively. You simply enjoy the craft a lot more that you enjoy the result of your craft.
There's nothing wrong with that, just as you can enjoy the effort and craftsmanship of hand-knitting a sweater. But some of us are more fulfilled by making nice clothes, and the labour (or delegation thereof) is a means to an end.
Another difference is the binary code - I can run the same agent on a different computing substrate (e.g. different CPU), but with humans no one can do that. That has implications, we can study or modify AI agent behavior, for instance.
"We'll just store prompts in VC and the agent will pick those up", "Code isn't going to exist anymore", "We will just write comprehensive specs of what the software is supposed to do"
This is short-sighted IMO. (Conversely, maybe my argument is short-sighted).
This is exactly why we use code... Natural language is ambiguous, to a fault. Any statement can impact depending statements in multiple ways, which creates this huge dependency graph that has millions, billions, trillions of "plausible" specifications.
It's pretty much ALWAYS going to be easier to just use a deterministic programming language to build the actual software.
We may never need to look at it, we may never need to write it, but having a deterministic specification of what a software system does seems like a much easier jump-off point to work with agents (whether or not we interface with the code).
Feels solved to me... A simple software example that creates users, logs them in, and shows them a dashboard turns into a TON of language and ambiguity.
Must be logged in to see dashboard datapoint A. Can log in with email or username. No log in if their IP is outside of [range]. Can log out. Logging out during a dashboard update cancels the transaction. Cannot see confidential data. Unless the user is an admin. User needs a strong password. Password must contain a capital letter.
Stuff like that just seems easier to parse + modify in code (whether human OR agent). Also, debugging natural language feels super icky. Which statement was it that got the password out of the formal spec?
And my biggest argument, we already HAVE code - reinventing the wheel for something that already works feels misguided?
Devil's advocate here: Why is having many possible implementations a bad thing? Sure, you don't want to half-ass your specifications and fail to pin down your product properly, but if you do pin down what matters, then by definition what remains is discretionary. Formal specs (e.g. the C spec) behave the same as informal specs in this regard.
The real question is whether humans in an agentic workflow can actually identify all of what's structurally and functionally necessary for their product. Either the spec writer must be expert, or the agent must be savvy enough to identify and collaborate with the non-expert. Right now, agents like to just plough through underspecification or bad ideas so that they can deliver as quickly as possible.
My argument is more of a forecast, and your last paragraph fits it correctly. I don't think we'll be able to maintain it once we get past a certain level of complexity. Or the maintenance / modification of that specification will be much more difficult to work with, to the point that we'll decide code is the solution.
When it comes to precision it's easier to express instructions in formal languages and I don't see that changing anytime soon unless natural language itself changes drastically, which I highly doubt. Formal syntax, well-defined semantics, reproducibility and composability are traits that make traditional programming languages more reliable and precise than natural language for programming.
Everyone's a lawyer now.
I like the idea that the code looks like English and is therefore readable, long ago I pitched a plan to make an “Inform 7 for European Air Traffic Regulations” where that readability was a big plus.
That's not even considering the fact that in practice if you were to make a proper game like that today, you wouldn't choose text input because of mobile. You would have some sort of touch input instead.
I do want to say that I like the fact that a game made in Inform7 is a file that runs on a separate emulator, and some browser-based implementation even exist. It's kind of like Java, or kind of like a webpage.
I wish there was something like that for small games in general. An application that you can download to your computer that runs a game file sandboxed, so you can safely play random games that aren't browser games because the environment doesn't provide an API for arbitrary file access. That's pretty much what I wish Flash was, as well.
Traditional coding is left for MCP tooling, and even that can be generated as well.
I've realized that the agent doesn't write 'good' code, instead my vague understanding of what I expect makes me think it does. When I look at the AI code, I see that there are more nuances and decisions that needed to be taken before writing the code. One would say that a spec would suffice, but then I remember TLA+, developed by Leslie Lamport to help developers think critically about their programs/algorithms. Sitting down and formally writing what I want to do helps me better understand the problem and come up with a real -not vaguely defined- solution.
No one writes 'good' code. Everyone only writes 'good enough' code. You should always assume the existence of flaws and bugs.
You call "good" code the one that doesn't have the mistakes you know. But you'll never know everything, even if you are as smart as Dijkstra.
First, it's bullshit, some code is better than others. Also, I wonder what caused that.
and in practice I find it _very_ effective to express key ideas with some formal language where applicable. a little ebnf here, some snippets of python or prolog there or other languages there. and I find llms wonderful at filling in the dots and, and that's the topic here, to translate our semi formal conversation into rigorous, formal language.
and I dare one step further: I also find llms useful in formulating and refining technical proposals, for human peer review and llm driven implementation, and of course these proposals mix natural language prose with semi-formal and formal detail. think PEP-12 and PEP-1 style. and these then get work packages which each loop in a spec as in sdd.
seems to work just fine so far :-)
I've been going through an identity crisis for a year now as I realize more and more that nearly the entirety of what I know comes down to arcane incantations producing transpilation instead of magic. My tech career was just converting specs from clients and employers into machine code, with extra steps.
To move now at the speed of thought and let AI complete whatever tedium was preventing me from getting real work done has been a revelation.
To the point that I fantasize about the day I can leave tech behind and get back to the human experience. No longer drowning in the unending workload that demands ever-increasing productivity for the same pay, but finally able to say enough's enough and provide time/money/resources for myself and eventually the community at large outside of the hierarchical economy.
If we can't automate our livelihoods with AI, then we don't have anything.
You spend more of both air and water than a DeepSeek flash does when with an NVL72.
Is all AI DeepSeek on NVL72?
Is the next evolution of AI mania really ”achtually, humans are the pollution and must be destroyed”?
Ask your mfing clanker. What do you think I am, grok?
Grok, please provide sources for the great-grandparent’s claims.
So while I also foresee and lament humanity's self-genocide, it seems a bit hypocritical to get salty about AI "automation" while broadly accepting our industrial civilization's trajectory.
They were trending downward in the US. AI usage in the US did change that single-handedly. I understand carbon emissions are a global problem but since they are subject to political remedies, the solution to the global problem is solving the same problem within each political jurisdiction.
Try to define a specific item like the closest cat to you so that anyone, just from reading the definition, can recognize that cat anywhere. You could write a whole book and not be done. Or you could stamp the cat with some id (symbols) in and refer to that. As long as that id is not repeated (rule), the system is ok.
Formalism is defining stuff, and add rigid rules that are consistent with each other. Once that done, it allows anyone to reach the same thinking location as the original person. Formalism is a knowledge transfer tool.
> My tech career was just converting specs from clients and employers into machine code, with extra steps.
If all you did was that, I’m quite sad for you as yourself should have automated your job to remove that tedium.
I would describe my job as designing a system that respect all the constraints of the situation. Some of them comes from specs, some comes from the technical platform, and some are just future possible interactions. The system is what I modify, coding is just how I do it.
When I see people abandon their work to AI, the other consequence is that they abandon their control of the system as well. They can’t explain how it works, what’s its reliability, and whether it can be improved (or part of it reused in another context).
I guess the thing about that process is, you inevitably complete an incomplete spec. There are always fine details that will never be decided until they're required to complete the implementation.
The expansion of knowledge is what ends societies and erodes civilization but produces religion.
Perspective of the religions is that I is the devil, the unaffiliated individual's perspective as opposed to we. All the religions teach fasting is abstaining from I want and pursuing we need.
We drive ourselves to the truth of what matters by eliminating waste as much as possible for 6 weeks
With specification driven development, the prompts need to be very detailed in order to produce exactly what is required.
Also gave me plenty of opportunities to go above and beyond. I miss when that felt safe.
You didn’t collaborate with other engineers? Or what if the spec you were given was unclear in places? Forgive me, but the style you describe sounds incredibly collaborative, super transactional.
Massive? My introduction to programming (from noob to beginner level) has been like only 10 books worth of content. Including some alternative pathways like 3D, security, system administration,... To this day, I don't think I've reached 50 books of materials. And If I counted everything it would be still small.
Human learning is very efficient (not time wise, but cost wise, and even training data wise).
Ah, yes, I can fondly recall reading and internalizing every word available on the internet when I was young...
Language models currently are mutated in the direction of exactly producing the desired output data, but gradually enough that they generalize across inputs in a way that appears understanding. It is more similar to compression, though, at least before a randomizing sampling strategy is applied during decode.
Anyway, circling back to my original topic: no organic being has the capability to integrate all the data arriving from their senses! They typically get more and more selective with experience, picking out only the pieces of information that are still important. Some are more selective than they're supposed to be, by choice or not (such as with dissociative disorders). In any case, the raw quantity of data coming through the senses becomes almost entirely irrelevant.
But for mature software eventually every single detail matters.
He's still quite correct. I generally see a machine as being "programmed in" whatever is tracked in source control. So as long as your git repo is tracking changes in Java, that's still programmed in Java, even if the Java was generated with the assistance of LLMs. I may consider the thesis of this article invalidated only when the majority of repos start tracking natural language rather than programming languages as the primary artifacts defining behavior of the software.
This means maintainability is as important as it is for hand-written code. Which varies, of course: there are plenty of valid use cases for one-off throwaway code. Just don’t assume checking in slop is suddenly cost-free “because AI”.
> the preferred form of the work to making modifications to it
Implies what you point to when you want to know where to make changes.
That wouldn't be a prompt - you might use a prompt to make changes, but the thing you're making changes to, certainly at present, is your java/python/rust++ /whatever codebase.
Lots of projects, even fully vibecodes ones, don't push and include prompts in their repos. But they all push the java code (sticking with java as an example for the sake of argument).
I can't imagine that working on a project where the java code is omitted, and people make changes to the software just by editing the prompts would go well. It's an interesting thought experiment, but I think you'd find it very hard to work on any kind of team where that was the practice.
Where do I point to when I want to know this? On a large and mostly LLM-generated codebase, I might dig through the code myself to find what needs to be changed where, but I would probably prefer to ask an LLM to do this.
Now if I had access to all previous prompts that were used in generating the codebase, it might very well be the case that I would prefer to work by changing those prompts and generating the whole thing again. In that case, the LLMs would basically turn into a compiler and the prompts would indeed become the new "source code". This is clearly not (yet?) a common approach to software development, but I wonder if it may become. Or should.
If one uses LLMs to generate the code, and others need LLMs to read the code, isn't this awkwardly close to someone publishing only compiled binaries and others then having to reverse-engineer these binaries in order to know where and how to patch them? Maybe the handicap is less grave, as the difference in strength of LLMs understanding code vs writing them isn't as huge as of decompilers decompiling vs compilers compiling code - but I think this difference still exists. It's still an advantage to have knowledge of the "secret" prompts that were used in generating the code.
It's excruciating to write, excruciating to read, and even legit geniuses with decades of hard won experience still leave room for essentially infinite interpretation. laws and contracts are all still swiss cheese and can be made to demand or prohibit whatever the party with the most money or other influence wants.
The law is rather a complex set of guidelines which need to leave some space for interpretation, so that additional relevant information for the situation at hand can affect the decision.
What is a sandwich?
Only the legislated part of law is codified. In our American common law system, case law is, by definition, uncodified. So what judges are doing, is taking the codified legislation, and applying case law decisions in layers on top, to reach a final decision.
[1] For many people, the result is actually the mean not the best, but it's another topic.
Apart of natural evolution of meanings, look at Orwellian limitations some (cloud) models impose on is that our natural language program become illegal. Due to topic or combination of words the program needs to be flagged and soon likely reported to three leter agency.
Next, RMS would ask: can you make your own natural language program compiler from scratch? I know we have (very expensive) local models, but wait until GPUs get a propper online subscriptions to work and surveillance taps.
> "The virtue of formal texts is that their manipulations, in order to be legitimate, need to satisfy only a few simple rules; they are, when you come to think of it, an amazingly effective tool for ruling out all sorts of nonsense that, when we use our native tongues, are almost impossible to avoid."
I have observed several samples where the business, when provided with a natural language configuration opportunity, will wind up staring blankly at the textarea until the original developer gives them a complete starting point.
I don't think "natural" language makes much of a difference unless you are already skilled in the art of developing useful engineering specifications. I often have to babysit the business through very basic boolean algebra concerns despite everyone having 3+ decades experience dealing with this stuff. Making everyone speak python could only make this worse, not better.
I use HN to keep myself warmed up on natural language expression. The difference between developers who post here prolifically and those who barely write one email a month is fairly shocking in my experience. If you intend to use a specific instrument to accomplish a complex task, you need to practice it constantly. Ideally every single day. There is no substitute for this. There never will be.
A lot of people lack “system thinking” when they can break down something into a set of elements and describe the relation between them. Once that done though , they can understand a part and manipulate it.
For some “system thinking” is innate. It can also be learned. But it’s a required quality in engineering where you need to create a solution where there was none.
The experiment in designing a language that resembled natural languages (English and Japanese) was not successful. -[1]- William R. Cook, AppleScript, HOPL IV
Now our new LLMs are different, because they don't use "language the resembled natural languages", but actual natural language. But the lesson is instructive nevertheless, because it gives us some empirical evidence to compare to Dijkstra's theoretical arguments.
And this is that natural language is at best a two-edged sword. Yes, there are benefits, but there are also huge drawbacks. And one problem is that the benefits are front-loaded and the drawbacks are long-term problems.
To me, one thing we are missing is that what LLMs do for us actually has 2 parts.
1. It allows us to use natural language, allowing us to be fuzzy.
2. It allows us to specify what we want at a much, much higher level than usual.
With our LLMs, these two are intrinsically linked. I think the whole would be much, much more valuable if we could separate them.
Tell me about it! This has only gotten worse in the meantime.
> From one gut feeling I derive much consolation: I suspect that machines to be programmed in our native tongues —be it Dutch, English, American, French, German, or Swahili— are as damned difficult to make as they would be to use.
Sadly, this is no longer true. The floodgates are open. And as it turns out, many people get really angry if you curtail their ability to talk nonsense, even if the result it supposed to be software.
It seems Dijkstra is describing potential calability of LLM model trained on published collective human knowledge enabled by the Internet
>and, in view of the history of mankind, it may not be overly pessimistic to guess that to do the job well enough would require again a few thousand years
Since the article was written in 1978 (about 50 years ago) and from the time the computing resources of CPU and RAM has increased exponentially until the LLM first appeared in 2020s, it seems the thousand of years prediction is merely several decades accelerated by the rapid advances of computer and communication systems technology spearheaded by companies like Nvidia.
Time flies like an arrow.
I saw the parade coming through the window.
For small programs that basically duplicate something else with a few tweaks, sure, natural language can be fine. "The same thing as A, but with a red border, and add a new button to do X." Beyond that things start to get tricky.
Interactive programming has far more value than natural language programming, and agents also give you that. An ambiguous natural language spec. that leads to the wrong result is less problematic when you can interactively correct the problem; "No, that button should have been on the left hand side." It is the new version of REPL.
transcribed by Tristram Brelstaff
revised Fri, 19 Nov 2010
And so seem to be the case with most of the other EWDs I looked at as well.It shipped as a free PostScript font with NeWS:
https://www.donhopkins.com/home/NeWS/fonts/Dijkstra.ps
https://lucacardelli.name/indexartifacts.html
(You have to click on the "Fonts" tab, there's no direct link to it.)
Dijkstra [.ttf (2013 updated version by Reuben Thomas)] [.zip (old PC)] [.hqx (old Mac)] [Preview.pdf]
A beautiful handwriting font of unknown origin, first popularized by E.W.Dijkstra. Excellent for slides that appear to be carefully written, and for short, deep technical notes.
https://lucacardelli.name/Artifacts/Fonts/Pc/dijkstra.ttf
https://lucacardelli.name/Artifacts/Fonts/Pc/Dijkstra.zip
https://lucacardelli.name/Artifacts/Fonts/Mac/Dijkstra.sea.h...
In order to make machines significantly easier to use, it has been
proposed (to try) to design machines that we could instruct in our native
tongues. This would, admittedly, make the machines much more complicated,
but, it was argued, by letting the machine carry a larger share of the
burden, life would become easier for us. It sounds sensible provided you
blame the obligation to use a formal symbolism as the source of your dif-
ficulties.
How does one even achieve that with a manual typewriter?Clearly it is possible to "program" in natural language. I have one- and few-shotted a number of apps that meet my requirements.
Generally as the number and complexity of requirements grows it becomes harder to parse them if they are in a poorly structured natural language format.
I can't think of a time that I have provided specifications in natural language with sufficient rigor that if I was to run the prompt ten times, the ten generated programs would look identical or provide exactly the same outputs for the same inputs under all situations.
Whenever I find that I need the rigor such that the code could be considered to be a cache, not an authoritative artifact, I find domain specific languages to help me to ensure the comprehensiveness of my requirements around the dimensions that I care about.
I also find such structure to aide collaboration with other humans trying to understand or extend such specifications.
So I think for code to become ephemeral, for substantial pieces of software that require the documentation of many complicated requirements, writing such specifications in natural language is not the best interface and would require substantial support from LLMs to project them in ways (flow charts, UX demos, etc) that humans could reliably understand and mutate them without introducing regressions.
But we'll see. Last year I still thought git was an appropriate version control system to use!
That could just as easily be written today
How many times have we seen that there's been a spec for something and the programmers write something that is exactly like the spec said but was completely wrong?
It is perhaps for the best that Djikstra did not live long enough to witness this problem become orders of magnitude worse.
The old skeptics weren’t wrong about the foolishness of natural language as a programming language, it's just that they assumed the only possible intermediary way to "write" code was something compiler-like! they never really thought about a future where ai would become good enough to translate natural language instructions into runnable code
Yes it all started with "natural language", but even AI has an understanding that you need more structure than natural language when you want deterministic results.
In this way, the generated output, whether used as a proper program or just some scripts to do small activities, they can be audited later, reused, and tested even if a client created the request in plain language.
We would then mostly be translating bugs from english to the underlying language and bugs would mostly be people speaking ambiguously or just misspeaking
I've been stating it elsewhere, attention has made English into a context aware sensitive programming language by resolving ambiguities through anaphora and coreference resolution. Inform7 did limited anaphora resolution - it - but LLMs are able to resolve "move that file to this folder".
Anyway, my work process is as follows: I have the agent write the code, and describe it's purpose etc. via comments so another session can later pick it up easily without me having to explain everything again. That's what I commit. Sometimes I even look at the code :)
What else could I commit? At the current state of the art, I could commit the whole natural language session that lead to the code, instead of the code. When I later check this out in a fresh environment (without the artifacts the LLM putted out), I'd just load the most recent version of the conversation as an initial prompt. Or I could want to check out the conversation at a point two months ago and rebuild the program from there.
Would that produce a program with exactly the same behavior? I don't know. But if it doesn't, the essay's argument is not moot. Not yet ...
That being say, I really like the idea of committing our prompts. I can see a possible future in which that would be our work: write precise specs so that you can generate the program again with an other model, in an other programming language, and get the same behavior. Which sounds a hell lot like… a RFC. :)
We may be the culprit here, by the way. Maybe the only thing missing is us taking "prompt engineering" more seriously. It would be specification writing, really, or protocol design. I think it might already be possible, from an experience I had. I made Codex write a POSIX vi implementation from POSIX ex/vi specs. It took it a week-end, but I now have a POSIX vi, with only added on top multilevel undo/redo and syntax coloration, and without the baggage and instability of nvi2, I'm an happy man. I've been using it for more than a month and still have to find a fault to its POSIX implementation (and there are _a lot_ of details in POSIX vi specs). I think models are already there, when it comes to implemented behavior predictability, it's just us who are not precise enough in our specifications.
Consider the role of a Business Analyst, in corporate environments. He is the person that talks to stakeholders and users and translates their "natural language" wishes into piles of semi-formal language (UML anyone?). Later on this will become fully formal language.
But I think Dijkstra point is more that we can't fully automate this process and let the machines do the formalization thingy. I used to believe that but I've seen LLMs doing things that really, really surprised me.
In the end I still hold hope in the old saying: "make a something idiot-proof and someone will just make a better idiot". We see LLMs doing magic if they're used by people that know what LLMs are doing. I never saw LLMs doing magic in the hands of idiots.
AFAIU this particular chain is not compromised.
What a spot-on sentence.
I could only describe the "look and feel" of the ESP32-algorithm driving a sewing machine: "Snappy but not jerky, linear at low speeds, but accelerates fast".
Antigravity made it perfect but incomprehensible for a hewman.
Dichotomy solved, let’s go get lunch! ;-)
The problem with this argument isn't that natural language programming leads to vague/ambiguous code that would lead to errors. The problem is that the machine does not inform you of the ambiguity. Rational humans do just fine when they interact because they can identify these problems. Programming would work just find if context were identify and clarified while the code was being written.
If I were to tell a program to "buy political ads in Portland," yea, the point is that the program would need to know which Portland I mean. Otherwise it might accidentally think I mean Portland, OR, instead of Portland, ME:
https://www.yahoo.com/news/politics/articles/25-000-mistake-...
Humans can do the same thing if they're not being careful. The point is, the vast, vast, vast majority of time, someone would just say "wait, you mean Portland, Maine, right?" and you'd say "yes" and that would be that.
Hence, when communication via formal text results in nonsense, it is very clear that the originator of that nonsense is you. With LLM-generated code the nonsense may be much less obvious and when it does surface, you can feel like it's not your fault at all. You are a genius and the LLM fucked it up. No wonder all kinds of "developers" want their code generated by LLMs and don't even look at it anymore. It's the ultimate responsibility laundering.
This argument makes the implicit assumption that humans are uniquely able to convert between this "customer wants a program that solves their problem" level and compileable code. That was a reasonable thing to believe in 1978, but is not a reasonable thing to believe in 2026.