{"slug": "where-the-compiler-stops", "title": "Where the Compiler Stops", "summary": "Google's blog post argues that Go is ideal for AI-assisted software engineering because its compiler provides a deterministic feedback loop for code verification, shifting the bottleneck from writability to verification. The article suggests that languages with algebraic type systems, such as F#, Rust, Swift, or OCaml, can encode business rules into types, making illegal operations fail at compile time, which is more reliable than runtime checks in dynamic languages.", "body_md": "# Where the Compiler Stops\n\nGoogle recently published a piece titled \"[Why Go is an ideal language for AI-assisted software engineering.](https://developers.googleblog.com/why-go-is-an-ideal-language-for-ai-assisted-software-engineering/?ref=blog.bencope.land)\" I recommend giving it a read. It makes a compelling, practical point that anyone building production systems with LLMs eventually collides with: when machines write code, the primary bottleneck shifts from writability to verification.\n\nPython is unmatched for human prototyping, but in an automated generation loop, dynamic typing and implicit runtime state are liabilities. Go solves this by wrapping the model in a tight, deterministic feedback loop: fast compilation, rigid formatting (gofmt), low syntactic variance, and static type checks. The compiler acts as an automated sanity check before code ever reaches a human reviewer.\n\nGoogle’s thesis is dead on. Static compilers and standardized formatting give models something to be checked against. If compiler feedback is where verification happens, the next question is how much a compiler can verify.\n\nGo uses its compiler and static type system to enforce syntactic and structural correctness. This is where language preference has concrete ramifications. In an agentic coding loop, the compiler is effectively another source of context. Every rule it understands is a rule the LLM does not have to remember from a prompt, recover from documentation, or rediscover through a failing test. The richer the domain encoded in the type system, the richer the deterministic feedback returned to the model when it gets that domain wrong.\n\n**Business Logic as Compilation Correctness**\n\nCompilers check if the code *can run*, while dynamic validation, tests, and human discipline check if the code *does what the business intended*. A model writing code produces syntax that's valid and rules that aren't yours. Runtime validation catches that on the day it runs in production, assuming someone wrote the check for a case nobody anticipated.\n\nIn a well-designed domain model in a language with an algebraic type system (like F#, Rust, Swift, or OCaml), the business rules and the type definitions are the same artifact. An operation the type model makes illegal won't compile, so the check happens before the code runs rather than in a test someone remembered to write.\n\nPut the rules in the types and the guards move out of the function bodies. A payment that requires human sign-off doesn't get an `if (!isApproved)`\n\ncheck inside the execution path. `ExecutePayment`\n\ntakes an `ApprovedOrder`\n\n, and the only way to construct one is through the authorization step. An agent asked to execute an unapproved payment writes code that won't build.\n\nThe same applies to the small stuff. `TenantId`\n\nis `TenantId of Guid`\n\n, so passing a `UserId`\n\nwhere a tenant is expected fails at compile time. In a dynamic language that's a silent authorization bug that ships and gets found by a customer.\n\nCorrectness stops being something you remind the model about in a prompt and becomes the only shape the compiler will accept.\n\n**Why LLMs Naturally Reason About Algebraic Data Types**\n\nLLMs are language models. People ask them to do arithmetic and produce exact byte sequences and then act surprised when the output drifts. They are experts at language, and a domain expressed as language is home ground.\n\nWhen you ask an LLM to generate code in an imperative or class-heavy paradigm, it has to navigate deep inheritance hierarchies, factory pattern boilerplate, and implicit mutable state. This consumes context window capacity on plumbing rather than domain logic.\n\nAlgebraic Data Types, specifically Discriminated Unions (DUs) and single-case domain types, mirror natural language specifications far more cleanly.\n\nConsider how an order processing domain is defined in F#:\n\n```\ntype OrderArtifact =\n    | OrderSubmitted of SubmittedOrder\n    | InsufficiencyDetected of InsufficiencyDetails\n    | ActionProposed of ProposedAction\n    | ExecutionCompleted of ExecutionReceipt\n```\n\nOr similarly in Swift:\n\n```\nenum OrderArtifact {\n    case orderSubmitted(SubmittedOrder)\n    case insufficiencyDetected(InsufficiencyDetails)\n    case actionProposed(ProposedAction)\n    case executionCompleted(ExecutionReceipt)\n}\n```\n\nThe code doubles as a specification a domain expert can read. Every state has a name the compiler knows about. Pending approval is a case in a union rather than a string someone has to spell correctly in eleven places. Values arrive fully constructed, so runtime null checks fall away, and anything coming out of a lookup already has a type by the time you touch it.\n\n## Compiler Errors as Prompts\n\nIn an agentic coding loop, compiler errors aren't merely diagnostics for a human developer. They are prompts generated deterministically by the program the model is trying to write. A compiler that understands only syntax reports malformed syntax. One that understands the states and transitions of a domain reports an implementation that doesn't cover them. The more meaning we move into the type system, the more meaningful the repair signal becomes.\n\nIf an LLM generates a Go snippet with a typo or structural type mismatch, `go build`\n\nprovides a clean error message that the model can use to repair its output. But an ADT-driven compiler can put domain vocabulary directly into that feedback:\n\nTreat warnings as errors and the agent cannot declare success without accounting for `InsufficiencyDetected`\n\n. This is importantly different from telling the model in a prompt that insufficiency is possible. Prompt instructions are context the model is expected to remember. The compiler error is evidence that the artifact it produced does not satisfy the domain model. The model generates code, the compiler checks it against the domain model, and any failures become context for the next attempt.\n\nAs an aside, F# has FSI. An agent can load a domain model into the REPL and exercise it against real values without wiring any of it into an application. It doesn't have to build a project to find out whether its own design holds. Compilation says the code is consistent. FSI lets the agent interrogate that design before it writes the surrounding implementation.\n\n## Where the Compiler Stops\n\nLanguage choice in AI-assisted software engineering goes beyond the question of which language is easiest for a model to generate. What matters is what deterministic machinery surrounds the model after it generates something. Algebraic domain modeling lets us push more into that machinery.\n\nIf `TenantId`\n\nand `UserId`\n\nare different types, the compiler can reject their substitution. If an operation requires an `ApprovedOrder`\n\n, the compiler can reject attempts to execute a merely `SubmittedOrder`\n\n. If `InsufficiencyDetected`\n\nis a possible state, exhaustive pattern matching can reject code that pretends it doesn't exist.\n\nWith the business modeled correctly, the LLM writing the code no longer has to independently remember every rule we encoded. The compiler remembers it for us. Fast compilation makes a good repair loop for generated code, and rich domain types make the feedback from that loop increasingly about the program we meant to build.\n\nThe question, then, is how much meaning we can put into compilation.", "url": "https://wpnews.pro/news/where-the-compiler-stops", "canonical_source": "https://blog.bencope.land/where-the-compiler-stops/", "published_at": "2026-08-17 21:27:15+00:00", "updated_at": "2026-08-17 21:41:10.258009+00:00", "lang": "en", "topics": ["artificial-intelligence", "large-language-models", "developer-tools"], "entities": ["Google", "Go", "F#", "Rust", "Swift", "OCaml"], "alternates": {"html": "https://wpnews.pro/news/where-the-compiler-stops", "markdown": "https://wpnews.pro/news/where-the-compiler-stops.md", "text": "https://wpnews.pro/news/where-the-compiler-stops.txt", "jsonld": "https://wpnews.pro/news/where-the-compiler-stops.jsonld"}}