Choosing a language when the AI writes the code

September 3, 2026

Choosing a language when the AI writes the code

September 3, 2026
Choosing a language when the AI writes the code

TL;DR

  • You no longer need to know a language to ship code in it, but the language you pick still decides how much of the output you have to check. That is the cost nobody budgets for.
  • Four things drive the gap, and none of them is about how good the language is: training data volume, strict compilers punishing near misses, paradigm bias in public code, and invented functions in fast-moving library ecosystems.
  • Treat mainstream output as a first draft you review. Python, TypeScript, JavaScript and Java land here. Treat niche output as a suggestion you verify line by line, starting with whether the functions it called are real.
  • A low benchmark score is not the same as a model that cannot write the language. Rust and Swift fail benchmarks on compiler strictness where a reviewer would have said "nearly there, fix line 12".
  • If you are costing a Python-to-Rust rewrite, add a line for review cycles. The savings are real. They arrive later than the pitch deck assumed.

The language you choose now decides how much of the output you have to check

AI-assisted programming, or vibe coding, is not a fad. It is here to stay. The days of spending long hours staring at a couple of lines of code trying to work out why they do not do what they obviously should are almost gone, and almost anyone can write code now.

Seasoned programmers get more out of these tools rather than less, which is not the way the story usually gets told. Experience is what lets you drive the model to the answer you want, and it is what lets you look at the result and tell whether it is any good.

The genuinely new part is that you no longer need to know the language you are writing in. I never learnt Java. I never liked the language. But I can read it well enough to review code and approve pull requests, and nothing now stops me from using coding tools to write an entire application in it. Or in Rust, or R, or whatever else the problem seems to call for.

The question is whether I should.

Because the model is not equally good at all of them, and the gap is wider than most teams assume when they pick a language. It does not show up as the model refusing. It shows up as output that looks right, takes longer to verify, and costs you review cycles you did not plan for.

Four things make a model stronger in one language than another

None of them is about how good the language actually is.

Training data volume sets the floor

Public repositories are overwhelmingly Python, JavaScript and Java. GitHub, Stack Overflow, every tutorial site you have ever landed on from a search. A model trained on billions of tokens of Python has seen every idiom, every awkward edge case and every bad idea somebody committed at 2am on a Friday.

Feed it a language with a few million tokens in the corpus and it is working from a much thinner sample. You still get output. It just shifts from confident to plausible looking, and telling those two apart is now your problem.

Strict compilers punish near misses, which distorts the leaderboards

Benchmarks score whether the code executes, not whether the intent was sound. Python and JavaScript will cheerfully run something with minor structural flaws. Rust, Haskell and C++ reject the whole file over a lifetime annotation or a missing trait bound, even when the algorithm underneath is mathematically correct.

The benchmark records a hard failure where a human reviewer would have said "nearly there, fix line 12". Worth keeping in mind the next time you look at a leaderboard and conclude that a model cannot write Rust. It can. It just does not get partial credit.

Paradigm bias means functional languages come out wearing the wrong shape

Public code is mostly procedural and object oriented, so that is the shape these architectures absorb best. Pure immutability, pattern matching and monadic composition are all badly underrepresented by comparison.

You see the result the moment you ask for idiomatic Haskell or Elixir and get imperative logic wearing functional syntax. It compiles, sometimes. It is rarely what somebody fluent in the language would have written, and it is usually harder to maintain than what you would have written yourself.

API churn is where the hallucinated functions come from

Mainstream ecosystems rely on stable, standard libraries. requests, express and numpy have looked broadly the same for years, so the model holds a consistent picture of them.

Niche languages tend to have fragmented libraries that move fast, and when the model reaches for something that is not there, it fills the gap with a function that sounds exactly like the one that ought to exist. That is where most API hallucinations come from. Not a missing fact, but a plausible pattern extended one step too far.

Put the four together and you get the practical rule: treat generated code in mainstream languages as a first draft you review, and generated code in anything niche as a suggestion you verify line by line, starting with whether the functions it called are real.

Four tiers, and only the first one is a first draft

Roughly, models are strongest in Python, JavaScript/TypeScript and Java, competent in C++, C# and Go, and drop off sharply in Rust, the functional languages and the lower-resource scripting tools. The tiers below are my own reading of that, informed by multilingual benchmarks such as McEval, which covers 40 languages and publishes a live leaderboard. They are a judgement about review effort, not a benchmark result.

Review effort rises as language support falls Four tiers of programming language. Tier 1, Python, JavaScript, TypeScript and Java, needs a normal code review. Tier 2, C plus plus, C sharp, Go and PHP, needs review plus close attention to memory and framework boilerplate. Tier 3, Rust, Swift and Kotlin, has sound logic but repeated compiler iteration. Tier 4, Haskell, Lua, Julia, Racket and Assembly, must be verified line by line including whether the library functions exist. The lower the tier, the more of the output you have to check TIER 1 Python, JS/TS, Java normal review TIER 2 C++, C#, Go, PHP review, plus memory and framework boilerplate TIER 3 Rust, Swift, Kotlin logic usually sound, but repeated compiler iteration to get it building TIER 4 Haskell, Lua, Julia… verify line by line, starting with whether the library functions it called actually exist
The tiers are about review effort, not about which language is better.
How much of the output you end up checking
Tier Languages What the output tends to look like
1. High Python, JavaScript, TypeScript, Java Idiomatic code, standard libraries handled seamlessly, edge cases usually accounted for. Review it the way you would review a competent colleague's pull request.
2. Moderate C++, C#, Go, PHP Core algorithmic logic is strong. Error rates climb around pointer arithmetic, memory management and framework-specific boilerplate, so that is where the review time goes.
3. Strict execution Rust, Swift, Kotlin Logic is generally sound but benchmark execution rates are low, because the compiler rejects the file outright over things like a lifetime mismatch. Expect iteration, not rewriting.
4. Low Haskell, Lua, Julia, Racket, Assembly Frequent hallucinated APIs, synthetic syntax that is not quite the language, non-idiomatic patterns, and high failure rates on anything functionally complex.

The tier boundaries move as models improve, and they move faster for languages that are gaining public code than for languages that are not. Treat this as a snapshot with a direction of travel, not a fixed ranking.

What this changes is the rewrite maths, not the language you love

Rust has been sitting on my TODO list for years. I have never learnt it properly, though I admire it from a distance. It is fast, close enough to C that the difference rarely matters, and there is no shortage of reports from peers and other companies about the money they saved by rewriting hot paths in it. The case for Rust is real, and nothing above is an argument against it.

But if you are budgeting for a rewrite of your Python application, add a line for this: the LLM you have standardised on is probably weaker at Rust than it is at the Python you are leaving behind. The savings are still there. They just arrive after more review cycles than the pitch deck assumed.

Plan for that, or you will discover it the expensive way, usually at the point where the migration is half done and the schedule is already public.

Where to start

  • Work out which tier your target language sits in before the language decision is final, not after. It is a review-cost input, alongside performance and hiring.
  • If the answer is tier 3 or 4, budget the review cycles explicitly in the plan rather than absorbing them as a surprise.
  • Make dependency verification a standing review step for anything below tier 1. Check the functions exist before you check the logic.
  • Do not read a low benchmark score as "the model cannot do this language". Check whether the failure mode is compiler strictness or genuine confusion, because those need different responses.
  • Keep the choice under review. The gap narrows unevenly, and a decision made on last year's tiers may not hold.

None of this argues for staying on the language you are on. It argues for pricing the move honestly.

I, for one, welcome our new robot overlords.

Frequently asked questions

Which programming languages are LLMs best at?

Python, JavaScript, TypeScript and Java. These dominate public code repositories, so models have seen every idiom and edge case in them, and the standard libraries have been stable long enough for the model to hold a consistent picture of them. Output in these languages is usually idiomatic and can be treated as a first draft to review rather than something to verify line by line.

Why are LLMs worse at Rust than at Python?

Two separate reasons that are easy to confuse. There is less Rust in the training corpus than Python, so the model is working from a thinner sample. Separately, the Rust compiler rejects an entire file over a lifetime annotation or a missing trait bound, so output that is logically correct still fails to execute. The first is a real capability gap. The second is mostly a scoring artefact.

Does a low benchmark score mean a model cannot write Rust?

No. Benchmarks score whether code executes, not whether the intent was sound. Python and JavaScript run code with minor structural flaws; Rust, Haskell and C++ reject it. The benchmark records a hard failure where a human reviewer would have said "nearly there, fix line 12". Read low scores in strict-compiler languages as a sign of iteration cost, not incapability.

Why do LLMs invent library functions that do not exist?

Because niche ecosystems have fragmented libraries that move fast, and when the model reaches for something that is not there it fills the gap with a function that sounds exactly like the one that ought to exist. It is a plausible pattern extended one step too far rather than a missing fact. This is why dependency verification should be the first review step for any language outside the mainstream, before you look at the logic at all.

Should I let an LLM write Haskell or Elixir?

You can, but expect to verify all of it. Public code is mostly procedural and object oriented, so pure immutability, pattern matching and monadic composition are badly underrepresented in training data. Ask for idiomatic Haskell or Elixir and you typically get imperative logic wearing functional syntax. It sometimes compiles, it is rarely what a fluent developer would have written, and it is often harder to maintain than code you wrote yourself.

Does this mean I should not rewrite my Python service in Rust?

No, it means you should price the rewrite properly. The performance and cost case for Rust is real and well evidenced. But the model you have standardised on is probably weaker at Rust than at the Python you are leaving, so the delivery estimate needs a line for additional review and compiler iteration. The savings still arrive, just later than the business case assumed.

What is McEval?

A multilingual code benchmark from Chai et al. (arXiv:2406.07436, 2024) covering 40 programming languages with around 16,000 test samples, created because most existing benchmarks focus on Python or translate their other-language samples from Python. It publishes a public leaderboard, which makes it a more useful reference point than single-language benchmarks when you are comparing model strength across languages.

Making a language or platform decision?

Digitalis.io provides expert consultancy and managed services across data platforms, Kubernetes and the wider cloud-native stack.

If you are weighing a rewrite, a migration or a platform change and want an independent read on what it will actually cost to deliver, get in touch at digitalis.io/contact.

Subscribe to newsletter

Subscribe to receive the latest blog posts to your inbox every week.

By subscribing you agree to with our Privacy Policy.
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.

Ready to Transform 

Your Business?