{"id":267,"date":"2026-09-28T13:38:27","date_gmt":"2026-09-28T13:38:27","guid":{"rendered":"https:\/\/jschuster.org\/blog\/?p=267"},"modified":"2026-09-28T13:38:27","modified_gmt":"2026-09-28T13:38:27","slug":"specifications-not-determinism-why-llms-are-not-compilers","status":"publish","type":"post","link":"https:\/\/jschuster.org\/blog\/2026\/09\/28\/specifications-not-determinism-why-llms-are-not-compilers\/","title":{"rendered":"Specifications, Not Determinism: Why LLMs Are Not Compilers"},"content":{"rendered":"\n<p>There are many legitimate criticisms to be levied at LLMs. The environmental damage, the unauthorized use of mass quantities of intellectual property, the decreased trust in our sources of information, and more are issues we should be deeply concerned about.<\/p>\n\n\n\n<p>However, there&#8217;s one problem that I think we&#8217;re mis-identifying: the notion that LLMs are nondeterministic.<\/p>\n\n\n\n<p>This most often comes up in the context of code generation. Some LLM enthusiasts will claim that asking an LLM to generate code from a prompt is no different than asking a compiler to generate assembly code from a higher-level language. Therefore, we shouldn&#8217;t have to review the LLM&#8217;s output. &#8220;It&#8217;s just another level of abstraction,&#8221; they say. &#8220;You don&#8217;t hand-write your assembly code or review the compiler&#8217;s output line-by-line, right?&#8221;<\/p>\n\n\n\n<p>The other side is quick to rebut: &#8220;But an LLM isn&#8217;t deterministic like my compiler is! It might generate different code each time I run the prompt, so how can I know what to expect?&#8221;<\/p>\n\n\n\n<p>The sentiment of that rebuttal is right, but the diagnosis is wrong. <em>Something<\/em> about LLM-based code generation is qualitatively different than traditional compilation. But the problem isn&#8217;t nondeterminism. Consider this statement:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>x = (1 + 2) * (3 + 4)<\/code><\/pre>\n\n\n\n<p>A compiler could translate that statement down to assembly code that looks roughly like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><span class=\"crayon-inline lang:default decode:true\">temp1 = 1 + 2\ntemp2 = 3 + 4\nx = temp1 * temp2<\/span><\/code><\/pre>\n\n\n\n<p>But the order in which we evaluate the expressions in parentheses doesn&#8217;t matter, right? So a sufficiently smart compiler could decide it&#8217;s more efficient to output this code instead:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>temp1 = 3 + 4\ntemp2 = 1 + 2\nx = temp2 * temp1<\/code><\/pre>\n\n\n\n<p>Same high-level program, two different assembly programs. That&#8217;s a nondeterministic transformation. Yet I bet you would accept either one without a second thought.<\/p>\n\n\n\n<p>&#8220;But the <em>behavior<\/em> of the program is still deterministic!&#8221;, you say. &#8220;Either way, we end up with x = 21.&#8221; Ok, then how about this program?<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><code>fn sleepAndPrintFoo():\n  sleep(1000)\n  print(\"foo\")\n\nfn sleepAndPrintBar():\n  sleep(1000)\n  print(\"bar\")\n\nfn main():\n  t1 = Thread.start(sleepAndPrintFoo)\n  t2 = Thread.start(sleepAndPrintBar)\n  waitForAllThreadsToComplete(t1, t2)<\/code><\/code><\/pre>\n\n\n\n<p>You can&#8217;t know which thread is going to execute first ahead of time: that depends on your OS&#8217;s thread scheduler. So this program might print &#8220;foobar&#8221; or &#8220;barfoo&#8221;. Either one is completely valid.<\/p>\n\n\n\n<p>So a traditional compiler has nondeterminism in both the transformation to assembly code, and in the observable behavior of the resulting program. Yet this still <em>feels<\/em> different from asking an LLM write a program from a prompt. Why?<\/p>\n\n\n\n<p>This feels different because programming languages and compilers have <em>specifications<\/em>. A specification is some statement of a program&#8217;s behavior that the author guarantees that the program provides. Sure, different language specs may be at different places on the rigor\/ambiguity spectrum from &#8220;fully formalized, mathematically defined spec&#8221; to &#8220;whatever the compiler does is the spec&#8221;. But in any of those cases, you can reasonably expect specific behavior from those compilers, and you&#8217;re justified in filing a bug if the behavior doesn&#8217;t match expectations.<\/p>\n\n\n\n<p>LLMs, though, don&#8217;t have that kind of specification. If we defined an LLM&#8217;s interface as a function &#8220;executePrompt&#8221; of type &#8220;String -> String&#8221;, what could the author of executePrompt guarantee to the user? Not much. We can say that <em>probably<\/em> the output will be something that looks like a plausible response to the input. But even that weak specification can&#8217;t be guaranteed to the same extent that we guarantee &#8220;(1 + 2) * (3 + 4)&#8221; results in 21.<\/p>\n\n\n\n<p>So that&#8217;s where we land, and that&#8217;s why &#8220;prompts are just another level of abstraction&#8221; doesn&#8217;t make sense to so many engineers. The whole concept of software engineering is built on the idea of abstraction and modularity: programming against a specified interface so that we can separate implementation details from intended behavior. When there is no specification, then there&#8217;s nothing to rely on, so we&#8217;re left trying to assemble a reliable system from unreliable components.<\/p>\n\n\n\n<p>Is &#8220;nondeterminism&#8221; versus &#8220;specifications&#8221; a nitpick about terminology? Yes, a bit. But if we&#8217;re trying to figure out how LLMs fit into the practice of software engineering, then I think it behooves us to correctly identify their shortcomings. Only the best possible diagnoses will help us find the best possible resolutions.<\/p>\n\n\n\n<p>So next time you&#8217;re talking about LLMs and the ways they might fit into software engineering, remember: nondeterminism per se isn&#8217;t the problem. We&#8217;ve been wrestling with nondeterminism for decades, and while it&#8217;s not easy, we have methods for handling it. But a lack of any kind of specification to describe what we can expect from that non-deterministic output? That&#8217;s a big problem, and requires a totally new kind of approach to handle.<\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>There are many legitimate criticisms to be levied at LLMs. The environmental damage, the unauthorized use of mass quantities of intellectual property, the decreased trust in our sources of information, and more are issues we should be deeply concerned about. However, there&#8217;s one problem that I think we&#8217;re mis-identifying: the notion that LLMs are nondeterministic. &hellip; <a href=\"https:\/\/jschuster.org\/blog\/2026\/09\/28\/specifications-not-determinism-why-llms-are-not-compilers\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Specifications, Not Determinism: Why LLMs Are Not Compilers<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-267","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/jschuster.org\/blog\/wp-json\/wp\/v2\/posts\/267","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/jschuster.org\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/jschuster.org\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/jschuster.org\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/jschuster.org\/blog\/wp-json\/wp\/v2\/comments?post=267"}],"version-history":[{"count":4,"href":"https:\/\/jschuster.org\/blog\/wp-json\/wp\/v2\/posts\/267\/revisions"}],"predecessor-version":[{"id":274,"href":"https:\/\/jschuster.org\/blog\/wp-json\/wp\/v2\/posts\/267\/revisions\/274"}],"wp:attachment":[{"href":"https:\/\/jschuster.org\/blog\/wp-json\/wp\/v2\/media?parent=267"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/jschuster.org\/blog\/wp-json\/wp\/v2\/categories?post=267"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/jschuster.org\/blog\/wp-json\/wp\/v2\/tags?post=267"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}