Quick Answer: Edsger Dijkstra argued in EWD 667 that natural language programming is a flawed goal. Native languages make it easy to state nonsense without noticing, and any interface that hides formal precision shifts work rather than removing it. Formal symbolism, he argued, is the tool that rules out nonsense, so its burden should be seen as a privilege.

Every few years, someone announces that we'll finally stop writing code and just tell the computer what we want in plain English. That dream has a long history, and it's older than most people think. Dijkstra wrote a short note about it in 1978, and his argument still holds up. Large language models now turn English prompts into working code, so his critique is more relevant than it was when he wrote it. Here's what he got right, where he was incomplete, and what it means for you.

The Long Hope for a Forgiving Machine

Dijkstra starts with a frustration that's almost as old as computing itself. Early programmers found machine code unforgiving. A computer does exactly what you tell it, even when a moment's thought would reveal an obvious mistake. Hoping for a more sensible machine, people built high-level programming languages, and those languages did reduce a certain class of silly mistakes.

The improvement was real but partial. Many errors that once produced quietly wrong answers now produced error messages. Dijkstra noted that some people hated those messages more than the wrong answers, and some still judged languages by how easily you could make undetected mistakes. That's the first warning sign: ease of writing and ease of being correct are different things.

COBOL shows how far the English-like ambition went. Its late-1950s design leaned on verbs like ADD and MOVE so business programmers could read their own code. Plenty of organizations still run COBOL today, and maintaining it is hard for reasons that have little to do with its vocabulary. The words looked like English, but the rules that governed meaning were just as strict as any other language's.

Here's the practical lesson. When a language promises to be more natural, ask what kinds of mistakes it now lets you make without noticing.

The Interface Doesn't Remove Work. It Moves It.

Dijkstra's core argument is about interfaces. Proponents of natural language programming assumed that if the machine carried more of the burden, the human's burden would shrink. He pushed back: an interface is not a fixed amount of labor divided between two parties. Cooperating across the boundary adds work of its own.

Consider a simple instruction: "Send the weekly report to the team every Monday, unless it's a holiday." A person can fill the gaps without thinking. A machine can't. Which team? Which holidays, and in which country? What happens if Monday is a holiday in one office but not another? Each gap you resolve becomes a new decision, and the machine's helpfulness can hide the fact that someone must make those decisions.

Dijkstra observed that this has happened repeatedly, and the software industry has responded by favoring what he called narrow interfaces. A narrow interface has a small, well-defined vocabulary, so both sides know what can be exchanged. This is why APIs use typed schemas and why databases use SQL instead of free text.

Here's where it gets interesting. A wider interface can increase work on both sides of the fence. The machine must guess more, and the human must check more guesses. You can see this in practice when an assistant produces plausible code that passes a quick look but fails in an edge case nobody specified.

Why Formal Symbols Rule Out Nonsense

Dijkstra's historical argument is the part most people skip, and it's the most persuasive. He pointed out that Greek mathematics stalled as a verbal and pictorial activity. Medieval scholasticism pursued verbal precision and never fully achieved it. The breakthroughs came from formal symbolism, developed by people like Vieta, Descartes, Leibniz, and Boole.

The reason is structural. A formal text can only be manipulated by a few simple rules. If you're solving 2x + 3 = 11, you have a handful of legal moves, and an illegal one is easy to spot. A sentence like "the system should be fast but thorough" offers no such check. Two careful readers can agree on every word and still disagree about what it requires.

This is why Dijkstra called formal symbols "an amazingly effective tool for ruling out all sorts of nonsense." Modern tools push the same idea further. Hoare logic lets you reason about program correctness with precondition and postcondition triples. TLA+, developed by Leslie Lamport, is used to specify distributed systems in a notation that tools can check. Z notation serves a similar purpose in formal specification.

Dijkstra also warned against a misunderstanding he saw in a 1977 technical report, which avoided standard logical connectives "for the sake of clarity." He thought that was backwards. Formal notation feels hard at first, but it's the thing that makes hard problems tractable for ordinary students.

Caveat: formal notation doesn't guarantee correctness. A precise specification can still encode the wrong requirement. Precision narrows the space of mistakes, but it doesn't remove the need to think.

Where the Argument Gets Contested

Modern practice complicates Dijkstra's position, and it's worth taking that seriously. Large language models can produce working code from a natural-language description. Many developers use them daily for boilerplate, scripts, and quick prototypes. The gap between "I described what I wanted" and "the program runs" is smaller than it was in 1978.

Dijkstra's argument still applies, but it targets a specific claim: that the naturalness of the input makes the task easier overall. Prompting a model is a different kind of interface from writing a program, and each has trade-offs. The table below compares common approaches.

ApproachWho carries the precision burdenHow errors surfaceTypical risk
Machine codeProgrammer, fullyWrong results or crashesSilent logic errors
High-level language (e.g., Python)Programmer, with compiler checksSyntax and type errors, runtime exceptionsPlausible code that is wrong at edges
SQLShared: declarative query, engine plans executionSyntax errors, unexpected result setsMisread joins or filters
Natural-language prompt to an LLMShifted to reviewer and testsOften only in review or productionPlausible output with hidden assumptions

The table shows the pattern. The natural-language row doesn't eliminate precision; it moves the checking to whoever reviews the output. The most useful version of the approach keeps a formal artifact in the loop, such as a test suite or a typed schema, so the machine's output can be checked mechanically.

That's the nuance Dijkstra would likely accept: natural language works well as a front end when something formal sits behind it.

The New Illiteracy and Your Specs

Dijkstra made a remark that many readers skip. He observed that many people in the Western world had lost mastery of their own language. He pointed to meaningless verbiage in scientific articles, technical reports, and government publications, and he called this "The New Illiteracy." His point was that anyone who believes natural language programming will work should first consider how poorly people use natural language now.

This matters because a prompt is only as precise as the writer's thinking. If a team can't write a clear spec in English, a model will fill the gaps with its own assumptions. The result looks confident and reads well, which makes the error harder to catch.

Here's a practical way to tighten a natural-language spec before you hand it to a person or a model:

  1. Replace every vague adjective ("fast," "secure," "user-friendly") with a measurable condition, such as "responds within 300 milliseconds at the 95th percentile."
  2. List every case the spec doesn't cover, and decide what should happen in each one.
  3. Name every term that could mean two things, such as "active user" or "holiday," and define it once.
  4. Turn at least one key requirement into a test case that would fail if the requirement were broken.

Step four is where the formal discipline comes back. A test is a small formal statement, and it's the part of the process a machine can check reliably.

What to Do With Dijkstra's Argument Today

You don't need to choose between natural language and formal methods. The useful question is which part of the problem each one should handle. Use plain English to state intent, the reasons a change matters, and the trade-offs you're willing to accept. Use formal artifacts for everything that must be exact, including types, schemas, invariants, and tests.

Here's a rule of thumb that holds up in practice. If a mistake would be expensive and silent, write it in a notation that rules out nonsense. If the cost of a mistake is small and visible, natural language is fine.

The question to ask, then, is not "Can the machine understand me?" It's "Can I check what the machine did, and would I notice if it were wrong?"

Frequently Asked Questions

What is natural language programming?

Natural language programming is the idea of instructing a computer in ordinary human language instead of a formal programming language. Dijkstra argued in 1978 that the idea misunderstands the role of formal symbols, which limit the nonsense you can express. Modern LLM-based coding tools revive the concept, but the precision problem remains.

Why did Dijkstra think natural language programming was foolish?

Dijkstra believed that native languages make it easy to make statements whose nonsense isn't obvious. He also argued that changing the interface doesn't reduce total work, because cooperation across the interface adds effort. Formal symbolism, in his view, is a privilege that lets people do hard reasoning with simple, checkable rules.

Can you do natural language programming with AI tools today?

Yes, to a useful degree. Developers routinely use AI tools to generate scripts, boilerplate, and prototypes from English descriptions. The output still needs review and testing, because models can produce plausible code with hidden assumptions. Tests and typed interfaces are the best way to catch those errors.

Is English-like syntax the same as natural language programming?

No. COBOL and similar languages use English-style keywords, but they still follow strict grammar and meaning rules. English-like syntax makes code easier to read, while natural language programming asks the machine to interpret open-ended human text. Dijkstra's critique applies most strongly to the second.

Closing Thoughts

The most actionable takeaway from Dijkstra's essay is simple: natural language is useful for stating intent, but precision still needs a formal home. Before your next natural language programming experiment, write one requirement as a test and run it against the output. Pass this to a teammate who's wrestling with a vague spec, and ask them to make one requirement measurable this week.