Building a Programming Language LLMs Can’t Use

One useful question when evaluating a programming language is whether an AI assistant can write it reliably. AI coding tools can draw on patterns learned from public code, but familiarity and correctness vary by model, language, task and available context. That raises a genuinely interesting design question: what would it take to build a programming language that large language models fundamentally struggle with? This article explores that question seriously — not as a way to protect jobs from automation, but as a lens for understanding why LLMs code well, where their limits actually are, and what those limits tell us about language design in general. Whether you are designing a DSL, evaluating niche languages, or just curious about the limits of automated code generation, the mechanics below will give you a concrete mental model.

Why LLMs Excel at Most Existing Languages

Large language models generate tokens conditioned on their input and learned parameters. Languages such as Python, JavaScript and Java have extensive public documentation and examples. Such material can help models learn recurring conventions, although the exact training mixture is not generally available for inspection. Familiar-looking output remains a proposal that needs checking, not a substitute for a parser, compiler or test suite.

This has three practical consequences:

  • Examples provide patterns to draw on. Consistent examples can help with common idioms, but their availability does not guarantee syntactically or semantically correct output.
  • Diagnostics can support correction. Compiler errors and failing tests provide feedback for another attempt. Success depends on the problem and the tools, and repeated attempts can still fail.
  • Ecosystem context matters. Documentation for libraries, conventions and failure modes can help an assistant produce code suited to the actual project.

A language can be easier to support through a combination of clear rules, consistent examples and accessible tooling. Release date alone does not determine difficulty: a newer language with a precise specification may be easier to work with than an older language used in a heavily customized environment.

What Actually Makes a Language Hard for LLMs

If you wanted to design a language that resists LLM assistance, you would not rely on obscurity alone. Scarcity of training data helps, but models generalize surprisingly well from related languages. Potential obstacles include non-local definitions, inconsistent examples and missing execution feedback. Their effects should be measured for a particular assistant and task rather than assumed.

Non-local definitions and extensible syntax. Parsing and meaning are distinct: even a language with a context-free grammar can have context-dependent name resolution and semantics. Raku provides custom operators and mechanisms for changing language grammar, described in its official slang documentation. An assistant working with such extensions may need definitions from other files, not just the current snippet. The difficulty is tracking those definitions and their effects; it is not adequately explained by saying that a model processes text linearly.

Semantic opacity. Operator overloading, implicit coercions, and heavily abstracted type systems mean the same characters can do radically different things depending on invisible context. Array-oriented languages such as APL illustrate how compact notation can require careful attention to shapes, ranks and evaluation rules. A model may produce syntactically plausible APL that is subtly wrong in ways that are hard for both the model and a human reviewer to catch.

Small or contradictory corpora. If the only public examples of your language are inconsistent — different dialects, breaking changes between versions, conflicting styles — an assistant may mix incompatible conventions and produce code that fits none of the supported implementations.

No executable feedback loop. Ironically, one of the most effective defenses is simply having no widely available interpreter or compiler the model (or an agent harness) can use to check its work. Execution feedback gives an assistant evidence for revising its proposal, although passing tests only establishes what those tests cover. A language without an easily installable toolchain denies them that loop.

A Concrete Design Sketch

Suppose you actually wanted to build such a language. Here is a sketch of design decisions that could increase the information an assistant needs, with the tradeoff each one imposes. This is a thought experiment, not a benchmark or an implemented language.

First, make the grammar user-extensible. Let developers define new operators and syntax rules that affect parsing of everything after their declaration:

// Hypothetical pseudocode, not executable Raku or another existing language
syntax left 40 "<|>" (a, b) = match a with
  | Some x => b(x)
  | None   => fail "empty"

let result = fetchUser(id) <|> (user => cacheLookup(user.id))

In this sketch, syntax left 40 declares a left-associative operator at a hypothetical precedence level. Assume fetchUser(id) returns Some(user) or None, and cacheLookup(user.id) returns a profile. The right operand is explicitly a function: the Some branch calls it with the user, while None raises an error. This is function application over an optional input, not a fallback between two values. An assistant needs these rules to interpret the expression; whether it succeeds is a question for evaluation, not an automatic consequence of custom syntax.

Second, make semantics data-driven. Let configuration files redefine core behavior, so identical code behaves differently across projects. This is what makes some real-world codebases hostile to AI assistance even in mainstream languages: heavy code generation, custom preprocessors, and build-time metaprogramming create a gap between the text the model sees and the program that actually runs.

Third, keep the corpus tiny and coherent — or deliberately fragmented. A small corpus may leave important cases undocumented; incompatible dialects add the risk of mixing rules. Supplying the right specification and examples can reduce either problem.

The tradeoffs are severe and worth stating plainly. These decisions can also impose costs on humans: they hurt IDE tooling, onboarding, code review, and long-term maintainability. A language that LLMs can't use is usually a language humans can't use efficiently either. The same missing information can hinder both an assistant and a human newcomer. The genuinely interesting territory is the small gap between them — syntax that is learnable for people with good tooling but statistically hostile for models — and establishing that gap requires comparative tests with clear tasks and success criteria.

The Practical Reality: Obscurity Is a Losing Strategy

It is tempting to conclude that niche languages offer job security or that "AI-proof" languages are a viable design goal. That conclusion does not follow from unfamiliar syntax alone. An assistant may receive a language specification, examples and compiler output as task context. Agent-based workflows can use that feedback to propose revisions. How effectively this works depends on the model and task; no claim of general competence across Rust, Haskell or APL is needed for the argument. To assess resistance, compare first-attempt output with tool-assisted attempts under a fixed time and execution budget.

There is also a strategic problem: if you build a language that AI tools cannot help with, you may increase the cost of developing autocomplete, automated refactoring and migration tooling. Those tools are not all based on LLMs, however: a language server and compiler can support them independently. You have optimized for a threat model that may not matter while accepting costs that definitely do.

The more productive takeaway is the reverse. If you maintain a niche language or DSL, the highest-value work you can do right now is make it more LLM-accessible: publish a specification, provide a grammar file for tree-sitter or an equivalent parser, ship rich error messages, and seed public examples. For syntax-aware editor support, a parser can be useful independently of any model. Tree-sitter documents its role as a parser generator and incremental parsing library; it does not by itself provide type checking or full language understanding. Clear language documentation supports human developers and can also provide useful context for AI tools.

Frequently Asked Questions

Is it actually possible to make a programming language that LLMs can’t use?

You can design tasks that may be difficult for a particular model, especially when essential definitions or tooling are unavailable. That does not establish that all LLMs are unable to use the language. Evaluate a specified model, task set and tool budget, and distinguish unfamiliarity from demonstrated inability.

Does using a niche language protect my job from AI automation?

A niche language alone is not a reliable guarantee of job protection. Tool support and task difficulty change, and human work involves more than syntax. Developing system design, domain knowledge and judgment is a more transferable strategy than depending on an assistant remaining unfamiliar with one language.

What makes a language especially LLM-friendly?

Clear specifications, consistent examples and an accessible toolchain give an assistant information and feedback it can use. Grammar alone does not determine semantics, and these properties do not establish a ranking of model performance across languages. Check usefulness against representative tasks in your own environment.

Should DSL designers deliberately resist AI assistance?

Choose a DSL design around domain requirements, clarity and verification rather than deliberate obscurity. AI assistance can be useful, but its output still needs review. For sensitive or correctness-critical work, define access controls and assurance requirements separately; unusual syntax is not a security boundary.

How can I make my own language work better with AI coding tools?

Publish a clear specification and grammar, provide a parser grammar and, where useful, an LSP server for editor features, write abundant annotated examples, and ensure error messages are precise enough for a model to act on. These investments also help human newcomers. For editor tooling, consider the documented capabilities and limits of a parser such as Tree-sitter rather than assuming a language server supplies every analysis feature.

Conclusion

The thought experiment of building a programming language LLMs can't use is valuable precisely because it fails instructively. Non-local definitions, opaque semantics and inconsistent examples can challenge both assistants and human newcomers. Their impact varies with available context and tooling. Specifications, compiler output and tests may give an assistant ways to improve its proposals; none guarantees correctness or establishes that obscurity will always fail. The practical lesson for language designers and developers alike is to stop thinking of AI as an adversary and start treating it as a second class of user. If you maintain a language or DSL, your next concrete step is simple: publish a machine-readable grammar and specification, and seed a corpus of idiomatic examples. Evaluate the resulting workflow against concrete tasks, record failures, and improve the specification or diagnostics before drawing broad conclusions about what models can or cannot do.



Transparency Note: Links in this article are not affiliate links. I recommend these tools and platforms based on their relevance to the topic, and no compensation is received for including them.

Privacy Overview

This website uses cookies so that we can provide you with the best user experience possible. Cookie information is stored in your browser and performs functions such as recognising you when you return to our website and helping our team to understand which sections of the website you find most interesting and useful.

Necessary

Strictly Necessary Cookie should be enabled at all times so that we can save your preferences for cookie settings.

Analytics

This website uses Google Analytics to collect anonymous information such as the number of visitors to the site, and the most popular pages.

Keeping this cookie enabled helps us to improve our website.