Comment by jdw64

7 hours ago

I'm also shifting to an vibe coding workflow, but I have a genuine question: whenever I use AI for Rust, it makes an insane amount of lifetime errors. I have no idea how people are churning out so many lines of code so quickly.

Honestly, despite all the hype around Rust in the community, the fact that AI can't handle lifetimes reliably makes me reluctant to use it. The AI constantly defaults to spamming .clone() or wrapping things in Rc, completely butchering idiomatic Rust and making the output a pain to work with.

On the other hand, it writes higher-level languages better than I do. For those succeeding with it, how exactly are you configuring or prompting the AI to actually write good, idiomatic Rust

> I'm also shifting to an vibe coding workflow, but I have a genuine question: whenever I use AI for Rust, it makes an insane amount of lifetime errors. I have no idea how people are churning out so many lines of code so quickly.

What harness and model you've been using? For the last few months, essentially since I did the whole "One Human + One Agent = One Browser From Scratch" experiment, I've almost exclusively been doing cross-platform native desktop development with Rust, currently with my own homegrown toolkit basically written from scratch, all with LLMs, mostly with codex.

But I can't remember a single time the agent got stuck on lifetime errors, that's probably the least common issue in regards with agents + Rust I come across. Much bigger issue is the ever-expanding design and LLMs being unable to build proper abstractions that are actually used practically and reduces the amount of code instead of just adding to the hairball.

The issue I'm trying to overcome now is that each change takes longer and longer to make, unless you're really hardcore about pulling back the design/architecture when the LLM goes overboard. I've only succeeded in having ~10 minute edits in +100K LOC codebases in two of the projects I've done so far, probably because I spent most of the time actually defining and thinking of the design myself instead of outsourcing it to the LLM. But this is the biggest issue I'm hitting over and over with agents right now.

  • Have you split your 100k loc codebases into smaller crates? If you take a look at eg gitoxide's repo, they've split it in many smaller crates. I think that might help with keeping the scope for the ai small and maybe help with keeping contracts tight and well-defined.

    • Yes, that absolutely helps (and yes, doing that :) ), I'm going even further and basically hard-enforcing a LOC limit per file too, which helps a lot as well.

      The complexities LLMs end up putting themselves in is more about the bigger architecture/design of the program, rather than concrete lines, where things end up so tangled that every change requires 10s of changes across the repository, you know, typical "avoid the hairball" stuff you come across in larger applications...

      1 reply →

A lefthook:

format: glob: ".rs" run: cargo fmt -- --check

lint: glob: ".rs" run: cargo clippy -- -D warnings

tests: run: cargo test

audit: run: cargo audit

+ hooks that shove the lefthook automatically in the ai's face

---

rustfmt.toml:

edition = "2021" newline_style = "Unix" use_small_heuristics = "Max" max_width = 100

The feedback loop is the interesting part, if you use standard software engineering practices (modularise, test/document your interfaces, etc) then I find things like Claude Code do an exceptional job: since they can actually run cargo check/test themselves and can validate the tests too.

I see the complete opposite. The lower level the language, the less babysit the agent. Pure asm is the best, only with very advanced SIMD flags it has problems. C is excellent.

But python or typescript are full of errors all the time. I rather fallback to perl than python. Perl has been excellent all along.

What kinds of programs are you writing and with what models? I'm curious if the lifetimes your programs require are trickier than most.

  • I'm actually vibe coding a game engine right now using a Hexagonal Architecture, and I ran into this exact same issue when trying to synchronize the feedback loop between the viewport and the editor. To be fair, I probably messed up the domain boundaries myself in the first place, but honestly, the AI-generated code wasn't very effective at solving it either

I'm surprised to hear this. I have not had any issues here at all. The AI might clone things but I don't really care/ mind, I can ask it to refactor to make things zero-copy after, which is how I've often written Rust myself. I've never seen it overly wrap things in Rc.

I've not done any particular/ special prompting.

> Honestly, despite all the hype around Rust in the community, the fact that AI can't handle lifetimes reliably makes me reluctant to use it. The AI constantly defaults to spamming .clone() or wrapping things in Rc, completely butchering idiomatic Rust and making the output a pain to work with.

This hasn't been true since around gpt-4.5 on the OpenAI side of things. The 5.x models have been pretty much solid on Rust for a while now.

I’ve been writing almost exclusively Rust with LLMs and rarely ever hit this. I guess maybe the kind of work you are doing?

Yeah, LLMs suck at named lifetimes. The number of times I have seen Claude reach for indices and clones instead of just using proper named lifetimes is too many to count at this point. Not great for high-performance code!

I wrote and maintain this library of skills and workflows called Rust Bucket[0]

It sets up your repo to ensure agents use a workflow which breaks your user requests down into separate beads, works on them serially, runs a judge agent after every bead is complete to apply code quality rules, and also strict static checks of your code. It's really helpful in extracting long, high-quality turns from the agent. It's what we used to build Offload[1].

0: https://github.com/imbue-ai/rust-bucket : A rusty bucket to carry your slop ;)

1: https://github.com/imbue-ai/offload

I think it's due to the lack of quality instructions on what is good Rust code; AI often literally doesn't know what idiomatic Rust is. It can be good to have a reference where you write the basic rules that you want it to follow (ideal to assume it has no idea why spamming clone is bad and you're speaking to someone who has just watched one of those youtube videos with a dude in black t-shirt speaking very slowly and going over basic programming concepts as if they're breaking you out of the matrix).

> whenever I use AI for Rust, it makes an insane amount of lifetime errors.

What model are you using, and what frameworks are you using?

This is not a hard problem for LLMs to solve.

Rust is nearly the perfect language for LLMs.

It's exceptionally expressive, and it forbids entirely the most common globally complex bugs that LLMs simply do not (and won't for some time) have the context window size to properly reason about.

Dynamically typed languages are a disaster for LLMs because they allow global complexity WRT to implicit type contracts (that they do not and cannot be relied on to withhold).

If you're going to add types, as someone pointed out earlier, why are you even telling an LLM to write Python anyways?

Rust is barely harder to read than Python with types. It's highly expressive.

You have the `&mut` which seems alien, verbose (safe) concurrency, and lifetimes - which - if you're vibe coding... you don't really need to understand that thoroughly.

You want an LLM to write code in a language where "if it complies, it works" - because... let me tell you, if you vibe code in a language where errors are caught at runtime instead of compile time... It will definitely NOT work.

  • It's not nearly the perfect language for LLMs and Rust is dramatically harder to read and reason about than Python with types. Other options work better for nearly all apps. I found Kotlin works well:

    - Garbage collected so no reasoning tokens or dev cycles are wasted on manual memory management. You say if you're vibe coding you can ignore lifetimes, but in response to a post that says AI can't do a good job and constantly uses escape hatches that lose the benefits of Rust (and can easily make it worse, copying data all over the place is terrible for performance).

    - Very fast iteration speed due to JIT, a fast compiler and ability to use precompiled libraries. Rust is slow to compile.

    - High level code that reads nearly like English.

    - Semantically compatible with Java and Java libs, so lots of code in the training set.

    - Unit tests are in separate files from sources. Rust intermixes them, bloating the context window with tests that may not be relevant to the current task.

    • Then your domain problem you’re trying to solve doesn’t benefit from Rust.

      Sounds like your work doesn’t need Rust and that’s ok.

      But don’t generalize.

    • Write a 250k LOC compiler in Python and then get back to me how well LLMs write in Python...

      Sure if you want to vibe code a TODO app where it's literally just copying and pasting one it's already seen 10,000 times before, it can do it in Python.

      1 reply →

Lots and lots of guardrails to not allow slop.

In tsz I have hard gates that disallow doing work in the wrong crate etc.

https://github.com/mohsen1/tsz

  • > have hard gates that disallow doing work in the wrong crate

    Maybe I'm using agents wrong, but I'm not sure how you'd end up in that situation in the first place? When I start codex, codex literally only has access to the directory I'm launching it, with no way to navigate, read or edit stuff elsewhere on my disk, as it's wrapped in isolation with copied files into it, with no sync between the host.

    Hearing that others seemingly let agents have access to their full computer, I feel like I'm vastly out of date about how development happens nowadays, especially when malware and virus lurks around all the package registries.

    • tsz is an experiment in giving coding agents full control. On my day job I am a lot more careful. But I've moved on from manually approving every change and instead review the final diff. I noticed manually approving was counterproductive.

      2 replies →

Honestly Rust is an UGLY language. For whatever powers it possesses in memory safety, its cryptic symbology is reminiscent of assembly.

This is a problem when language designers are mathematicians and don’t understand typographical nuance and visual weights.

  • Why would the language being typographically ugly matter? Python's pretty, but it hides a lot of functional nuance behind that. Rust is terse, but it's also expressive in its terseness.

    If you want to give it a fair shot, it does take some time to get used to, coming from something like Python or Ruby. I won't deny that. I've found that using LSP-assissted semantic syntax highlighting helps, for me, on the typographic front.

    I don't think typographic design is a key consideration in most languages' designs, though, and I don't think it should be. The main thing I look for is consistent, relatively predictable rules around the syntax, as far as that layer of language choice goes.

  • If I was forced to write it myself, then I'd agree, I'd use Clojure all day before Rust, because it's such a chore to write, edit and read.

    The whole "with AI" kind of reduces my hate for Rust though, and increases the appreciation for how strict the language is, especially when the agents themselves does the whole "do change > see error/warning > adjust code > re-check > repeat" loop themselves, which seems to work better the more strict the language is, as far as I can tell.

    The "helpful" error messages from Rust can be a bit deceiving though, as the agents first instinct seems to be to always try what the error message recommends, but sometimes the error is just a symptom of a deeper issue, not the actual root issue.

    • If I was forced to write it myself, i would love to keep writing ruby. What a wonderful language. I dont write ruby anymore, mostly using golang and python.. but ruby still a joy.

    • It’s funny I got downvoted immediately as expected.

      I mean God help us should a crustacean try to understand the merits of my claim.

      “Oh he’s saying something negative about rust…” Downvote!

      I think with AI the language should still be readable. Humans need to be able to understand what’s going on!

      2 replies →

  • I really don't get the complain about Rust's syntax, it's almost identical to TypeScript's and nobody complains about TypeScript Synthax being ugly …

    (Yes, I know the 'a lifetimes are a bit weird, and that's not something that exist in typescript, but that's also not something you use everyday in Rust either.

Clone is not "butchering idiomatic Rust", we gotta stop this nonsense

  • Sorry, should clarify. .clone() itself isn't inherently unidiomatic when used .

    My issue is specifically with how the AI uses it. In AI code, .clone() is almost always used as a brute-force escape hatch

    • So .clone() significantly reduces the mental overhead of using rust with a small performance impact? I'm intrigued :)

      Maybe it's harder to reason about the lifetime semantics while also writing code, and works better as a second phase (the de-cloning).

      1 reply →