Natural language is full of nuances and implicit cultural and domain specific connotations. LLMs work because they have been trained on massive corpus of materials that encode some (but not all) of those hidden meanings.
With specification driven development, the prompts need to be very detailed in order to produce exactly what is required.
Oh look at the last paragraph on the first page. Manually justified:
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?
It's not just em dashes, it's 1: typewriter em dashes aka `--` and 2: usage of them in pairs, like parenthesis, that is completely different from how LLMs use them.
> (You have only to look at the indeed alarming amount of on close reading meaningless verbiage in scientific articles, technical reports, government publications etc.)
It is perhaps for the best that Djikstra did not live long enough to witness this problem become orders of magnitude worse.
This article shows every now and then, and it's a must read. Indeed the natural language programming requires massive clusters of gpus just to make a half baked crud app
I send this article to everyone who tells me how English is now a high-level programming language, the next step up the chain from machine language to <their favorite language>. This analogy tends to be followed by "Just like most programmers never look at assembly code, looking at higher-level source code is going to become rare".
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.
You mean the English to code layer is stochastic while code to assembly is not?
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.
Arguing that two humans' distinct interpretations of a single specification is stochastic is patently absurd and requires, I think, some shred of evidence.
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.
Would they write the same code, if given the same spec? No? How about over multiple trials? No? Even the individuals' own code would differ from one trial to the next?
Well, then, their interpretations of the spec are stochastic. Good enough for me, anyway.
The term 'stochastic' refers to characteristics or properties that are measured and/or understood on a statistical basis rather than on an individual basis. What's your understanding of the term, since you seem to be using a nonstandard (or poorly-understood) definition?
Two people interpreting a specification in different ways isn't stochastic because human processing is not a statistical process in any meaningful way. Or, to put it another way: given a specification, you could not reasonably enumerate all the ways two humans might interpret it, much less assign statistical likelihood to those outputs.
As I said, "AI models don't replace compilers, they replace software developers" so yes, I agree that AI models are like humans.
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.
The same compiler will convert source to binary in different ways! Hermetic builds are hard!
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.
lol I saw the exact same JIT non determinism argument on reddit. The thing is, if JIT cannot replace a hotspot with a 100 percent functionally identical snippet of code then the JIT is just in time wrong and will be either patched, repaired or orphaned.
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!
"Time flies like an arrow" is a valid English sentence that one person can find numerous ways to interpret. A programming language that has the kind of ambiguous syntax that natural languages have would not be useful.
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.
Your acquaintances aren't changing their minds because the arguments are weak. Both the article and your comment assume that the only mode of interaction for natural language is a very high level description of programmer intent.
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.
The latter is also very far from specifying a calculator. And based on what we see in the "Show HN" projects, also very far from what the average person process is of using AI for generating software.
If AI is natural language programming then they already had it in 1978, because AI is in fact "asking a programmer to write code for you". And you can even ask them to do it at different levels of abstraction!
> 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.
>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.
>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:
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.
You misunderstood my comment - I meant that if instructing a programmer to program something is "natural language programming" (what AI agentic coding is), then they had "natural language programming" in 1978. I wasn't saying they had AI in 1978.
The magic sauce in intelligence is context-awareness. If a prompt is somewhat general ("make me a calculator") an AI should either ask questions, or make reasonable assumptions, or both.
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.
Some compilers can do that, but only in a shy way. For example Haskell's deriving or inference of the correct method called on typeclass. Or the Prolog/Datalog/SQL - they will also fill in many details on how to arrive at an answer.
> AI is natural language programming then they already had it in 1978, because AI is in fact "asking a programmer to write code for you". And you can even ask them to do it at different levels of abstraction!
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.
>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.
> Both the article and your comment assume that the only mode of interaction for natural language is a very high level description of programmer intent.
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.
>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
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.
The LLMs don't replace compilers, they challenge the next generation of compilers. And they don't replace software engineers, they shift them into yet another metasystem.
The LLMs use compilers, so I am not seeing the challenge here. Compilers do a lot of useful and important things like type checking and agents will typically check their output by invoking a compiler, then correcting errors reported by the compiler.
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.
> AI models don't replace compilers, they replace software developers.
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.
I recently vibe coded an application fully and tested it with users. So all the functional requirements were there.
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).
>Guess what wasn’t? The nonfunctional requirements.
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.
Yep and then you'll have some war stories how things break in production because they weren't initially included in the nonfunctional requirements. Have enough of these war stories and you'll basically be a software engineer. Albeit, a software engineer that has never coded before, but definitely someone who understands production issues.
I think the point is that it doesn't "just work" of you don't know what you are doing.
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.
It is, but software engineers have a much broader understanding of the problem, they also ask questions, and if they are good, they ask the right questions, something LLMs still have a problem with.
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.
> they also ask questions, and if they are good, they ask the right questions, something LLMs still have a problem with.
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.
"trust" and "responsibility" mean nothing for a fully digital entity who isn't required to feed its family, looking for an eventual new job, and being under pressure for not being fired
Code review, style guides, and a large set of tools like fuzzers that try to check for bad behavior before the code makes it into production. At least that's how it is done where I work and the use of agents to write code has not obviated the need for such a process (in fact we have added agents to that large set of tools and seen improvements in code quality as a result).
If you are checking every line written by an LLM , what would you estimate is the probability it would ever do this?? I look at most code still and I have a high level of trust that it would never do anything remotely similar to this.
Haha, well, I don't because I have no reason to assume this is in the code. In fact, I have reason to assume it is not in the code because the models aren't trained to produce this.
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 ;)
Well, I just used a contrived example to illustrate my point.
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.
"I work with models edit by edit" – That could be the cause of bias: Maybe because you're supervising small step iterations of the model, you notice issues that the model would have noticed itself if you had let it tackle a larger scope by itself. Worth a try in my experience. And the extra review agents make a big difference. Even if it's Opus reviewing Opus. Just by having a fresh context window, the model finds issues it created itself in another session. And with a different model, you get yet another fresh perspective. I find Codex is particularly thorough in reviews.
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 agree. I work in a similar way, and it is quite like managing developers. One difference though: I have no compunction against asking them to write incredibly tedious and long end-to-end tests exercising the user journeys with playwright and an actual db and backend. That helps a lot in making it more likely that regressions will not happen.
Thank you for articulating this!! This idea has been rolling around for a while but I haven't been able to put it into words.
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
You're welcome! I'm struggling with when and how to look at the code and what really matters now. I personally work across multiple codebases that each have teams of 5-7 developers, so someone else was always doing the work and I personally never could read or understand all the code.
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.
> 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.
'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.
If a compiler doesn't preserve the semantics of the program, that's a bug in the compiler. Programs in GCed languages mostly don't describe the behavior of how memory is managed and that is left to the compiler and runtime.
Your two sentences contradict each other. Programming languages decide what parts of the programme behaviour they want to specify, and what they leave to the implementation.
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.
It's applied to the programming language too - the given source can be compiled to unlimited number of possible machine code representations (it can different just by NOPs).
Yes, definitely. And the same program can run on completely different architectures. But it has a well-defined semantics that must be preserved by the compiler or runtime.
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.
It is all about definitions. Writing instructions for llms is a new activity and we can call it as we wish - but I like to think about it as a new type of programming language instead of thinking about it as something completely new, because many analogies do transfer - it is a way to instruct a machine.
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.
It is something completely new and we should be thinking about it as such. Analogies can help us here, and I think the analogy of "instructing a software team" is a much more useful analogy than "instructing a compiler" and the latter clouds our thinking.
> AI models don't replace compilers, they replace software developers
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).
I think this might be a false dichotomy, because for instance, I think LLMs are programmable in natural language, and they act as compilers, I even think they can replace programmers; but still I agree with Dijkstra, that programming in natural language is a bad idea.
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.
> 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.
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.
True, and as such it needs to be considered like any other code output from a one-off code generator, with at least minor added risks from non-determinism and, in the case of LLM-as-a-service, potential lack of model availability in the future.
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”.
That would be one definition of "source code". But then there's also the definition by the Free Software Foundation as "the preferred form of the work to making modifications to it". As prompting LLMs becomes the preferred form of making modifications, I wonder if a lot of open-source repos will unwillingly become "closed (prompting) source" over time, with intricate legal consequences.
I still don't know if I'd agree with you. I think:
> 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.
> Implies what you point to when you want to know where to make changes.
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.
And yet, the specification of almost every program in existence was communicated in natural language. At least between the customer and developer.
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.
Once an employer asked me to automatize his work, so the task that he did in weeks was done in seconds. I made a gui that showed every step he did manually, so he could check and understand every step. And yet he became confused and lost track of what the program was doing. He frequently asked me the very concepts he taught me so I could do the program. I just implemented exactly his specification. I didn't created any new concept, but as soon as the task became automatized, he stopped understanding.
What Dijkstra said still holds true, and the essence is consistent with Brooks' discussion on essential complexity vs accidental complexity. I do think one thing has changed, though: when someone asks AI to implement XXX with very vague English, the implicit ask is picking the best[1] ever solution that someone else has done to solve XXX. For instance, if I ask AI to extract the Japanese subtitle of Shirojima show and convert it to an epub with all the nantural and cultural explanations, I was assuming that AI will fill in the blanks and do a good job and AI did. This won't help expert, but does it matter? Being good enough can be good enough to take away many people's jobs.
[1] For many people, the result is actually the mean not the best, but it's another topic.
I find c++ very unnatural, since it's a giant collection of small rules in the end more complex than assembler. I can't remember the entire sintaxis, zoo of function decorators, undefined behavior, intrinsics which are just labels over asm instructions, Code golf sintaxis...
Fun fact: there are over 600 definitions of the word "run" and over 400 for "set".
But yeah, English is really precise enough for programming.
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?
If law was code, there would be no need for judges to make decisions. Instead, a "judge" would be someone making a mechanical derivation of the judgement given the situation and the law.
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.
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.
LLM interfaces on everything these days equates to touch screen on cars. It is definitely a useful tool, but generally speaking, that's not how you'd talk to your computer.
I've had the same view since coding agents appeared. LLMs are good for summarizing, thus I tend to use them to understand code. However, the more I understand a code base the more I tend to be more picky with the agent. While the less I know about the code base, the more open I am to let it do its thing.
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.
>We would need all the intellect in the world to get the interface narrow enough to be usable,
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.
App stores are approving an order of magnitude increase of new apps because people are now able to create them using natural language. End users are deriving great value from them. So this is settled?
I think the difference is between communicating to a purely mechanical being versus communicating to an intelligent entity: unlike programs, which are purely formal languages, we write textbooks and papers in a mix of human language and formal language. often we introduce "just formal enough" notations. and the intelligent reader will read in-between, inter legere literally means just that: reading in between. filling the gaps, connecting the dots.
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.
NL programming is foolish to me not on technical grounds but on practical ones. It is most valuable when the business wants to understand how an already working thing does its job.
I have observed several samples where the business, when provided with a natural language configuration opportunity, will wind up starting 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.
> 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.
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.
Todays natural language program won't work tomorrow due to unstable nature of natural language.
E.g. look at Orwellian limitations some (cloud) models impose on me that my natural language program becomes illegal. Due to topic or combination of words, it needs to be flagged (and soon likely reported to three leter agency).
I know we have local models, but wait until GPUs get a propper online subscriptions to work and surveillance taps. RMS would ask: can you make your own natural language program compiler from scratch?
The experiment in designing a language that resembled natural languages (English and Japanese) was not successful. -[1]- William R. Cook, AppleScript, HOPL IV
253 comments
[ 0.30 ms ] story [ 24.8 ms ] threadWith specification driven development, the prompts need to be very detailed in order to produce exactly what is required.
But for mature software eventually every single detail matters.
[1] https://www.cs.utexas.edu/~EWD/ewd06xx/EWD667.PDF
It is perhaps for the best that Djikstra did not live long enough to witness this problem become orders of magnitude worse.
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.
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!
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.
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.
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.
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.
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.
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.
[1] For many people, the result is actually the mean not the best, but it's another topic.
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?
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.
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.
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.
AFAIU this particular chain is not compromised.
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 have observed several samples where the business, when provided with a natural language configuration opportunity, will wind up starting 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.
E.g. look at Orwellian limitations some (cloud) models impose on me that my natural language program becomes illegal. Due to topic or combination of words, it needs to be flagged (and soon likely reported to three leter agency).
I know we have local models, but wait until GPUs get a propper online subscriptions to work and surveillance taps. RMS would ask: can you make your own natural language program compiler from scratch?
The experiment in designing a language that resembled natural languages (English and Japanese) was not successful. -[1]- William R. Cook, AppleScript, HOPL IV
[1] https://dl.acm.org/doi/10.1145/1238844.1238845