Learning a Programming Language in the Age of AI: A Rust Case Study

Why AI-assisted coding makes you faster but not better — and a zero-code, evidence-based method to actually learn Rust.

Key takeaways

The Paradox

Ask an AI to help you learn Rust, and it will happily generate code for you. That is the trap.

The evidence is now clear. In a field experiment with nearly a thousand high-school students solving math problems, giving them GPT-4 while they worked raised their scores by 48 percent during the session. The moment access was removed, the same students performed 17 percent worse than peers who had never seen the model. The AI was a crutch: it carried the thinking, so the thinking never happened.

The same pattern shows up in programming. In a controlled study of 69 novices writing Python, students with access to a code generator completed tasks faster and scored higher immediately, but a week later there was no meaningful difference in retention. And in observational studies, weaker students using generative AI tools felt confident while their actual metacognition—their ability to notice when they did not understand—grew worse.

Rust makes the problem acute. Its whole design is a set of invariants about memory: who owns a value, when a borrow is allowed, how long a reference can live. These invariants cannot be learned by reading generated output. They are learned by holding the model in your head and getting feedback on it.

This post is a method for doing exactly that, grounded in cognitive science, applied to Rust as the case study. It starts with what the good pattern looks like, then explains why it works.

A Concrete Session

Suppose the goal is to write a function that modifies an integer owned by the caller. Here is the shape of the good pattern — we will explain why it works in the next sections.

Notice what happened: the tutor forced the memory model (stack, copy), accepted a description in prose, gave the name only after the concept was articulated, and ended on the next layer of questioning. The session never once produced a line of code for you. And the retrieval effort—producing "reference" and "exclusive" from your own model—is precisely what makes the concept stick.

Why "Just Ask the AI to Explain" Fails

Reading an explanation feels like understanding. It is not the same thing.

Cognitive scientists distinguish two kinds of memory strength. Storage strength is how well a fact is encoded; retrieval strength is how easily you can pull it out right now. Studying—or reading an AI's fluent explanation—raises retrieval strength without guaranteeing storage. That is the fluency illusion: the more smoothly you read, the more you believe you know, and the less you actually retain.

The classic demonstration is the testing effect. People who restudy material score worse on a delayed test than people who quiz themselves—and restudying makes them more confident about it. The thing that feels productive is the least productive; the thing that feels like effort is what works.

There is a second, subtler failure: right-answer-wrong-reasoning. Ask an AI tutor "is my code correct?" and it can validate the output while you nod along, never noticing that your justification is wrong. You leave the session believing you understood a concept you have not. Illusions of competence are not detected by consumption. They are only detected by production: you must generate, explain, and defend.

So the goal of an AI learning companion is not to be smart. It is to be a well-calibrated opponent that refuses to do your thinking.

What the Science Says Actually Works

Decades of learning research converge on a short list of techniques with measurable effect sizes. The crucial meta-analytic finding is about guidance: unassisted discovery is actively harmful (effect size d = −0.38), while guided discovery is one of the best-supported interventions (d = +0.30). The answer is not "let the learner flounder" and not "hand over the answer". It is structured questioning that fades.

TechniqueEvidenceHow it applies to Rust
Retrieval practiceTesting beats restudying on delayed tests (Roediger & Karpicke 2006); beats concept mapping (Karpicke & Blunt 2011)Quiz yourself on what move does before looking anything up
Self-explanationMeta-analysis g = 0.55 (Bisra et al. 2018)Explain in your own words why the borrow checker rejects a snippet
Spaced repetitionDistributed practice beats massed (Cepeda et al. 2006); rated HIGH utility (Dunlosky et al. 2013)Revisit ownership at 1 day, 1 week, 1 month—not in one sitting
Worked examples + fadingExamples help novices, must be removed as expertise grows (Kalyuga et al. 2003, expertise reversal)Study one solved problem, then solve a sibling problem, then the target
InterleavingMixed practice beats blocked (Rohrer & Taylor 2007)Alternate &str/String, move/clone/copy within a single session
Desirable difficultiesBjork & Bjork: harder encoding leads to better retentionDeliberately avoid auto-completion; type it yourself

Two consequences follow. First, the AI must not give you answers, because answers are exactly the crutch the research predicts you will over-rely on. Second, your progress must be measured by spaced, effortful recall—not by "I get it now".

The Zero-Code Protocol

The method is a strict division of labor between you and the AI. The AI is a Socratic tutor. You do all the production.

The AI never writes code. No snippets, no corrections, no pseudo-code. If it catches an error, it asks a question that exposes the violated invariant. The single rule that makes this enforceable: an AI output counts as code if you could paste it into a .rs file and it would compile.

You describe the memory state before anything is validated. Rust is a language about memory; you cannot reason about it without the memory model. So the protocol requires a verbal memory schema before the AI will evaluate anything:

The AI is forbidden from saying "correct" or "wrong" until you have articulated this. Often the act of forcing the schema is the correction—you hear your own confusion.

Names are given, concepts are earned. Here the Socratic method hits a hard limit, and the protocol must be honest about it. A term like Pin is an arbitrary label. No chain of questions can make you guess it; the philosopher's Meno paradox applies: you cannot search for something you do not know exists. The research on Rust documentation is blunt about this—Crichton noted that the Vec docs listed 182 methods at the time, and you cannot derive split_at_mut by reasoning. So the rule is:

Errors are analyzed, not fixed. When the compiler rejects your code, the tutor walks you through which invariant you violated—not the patch. This is deliberate: research on debugging shows novices who find a bug fix it 97 percent of the time; their problem is detection and comprehension, not fixing. Training the read of the error is the highest-leverage skill there is.

The Rust Case Study

Rust is the perfect stress test for this method, because its concepts form a strict dependency chain. If you fake understanding of ownership, borrowing makes no sense, and lifetimes become impossible. Each layer below is a prerequisite for the next.

  1. Memory model: stack vs heap, values vs paths, undefined behavior.
  2. Ownership and moves: one owner, move transfers, drop on scope exit, Clone vs Copy.
  3. Borrowing and slices: shared vs exclusive, aliasing XOR mutation, permissions returned when a borrow ends.
  4. Structs, enums, pattern matching: match as the tool for exhaustive reasoning.
  5. String/&str, collections: owned data vs borrowed views, Vec, HashMap.
  6. Traits, generics, trait objects: impl Trait vs dyn Trait.
  7. Lifetimes — the first real wall. The data must outlive its references. This is the hardest layer for beginners, and the most counter-intuitive: scope is not lifetime.
  8. Error handling: Result, the ? operator, panic as a contract.
  9. Closures and iterators: capture modes Fn/FnMut/FnOnce.
  10. Smart pointers: Box, Rc, RefCell, interior mutability.
  11. Send/Sync, threads: what may cross a thread boundary.
  12. Async and Pin — the maximal complexity cliff. Pin exists because futures can reference themselves; moving a self-referential value silently corrupts it.

Every layer has a documented misconception that the tutor should actively probe. The most widespread: beginners think the borrow checker exists to prevent data races. It does not primarily do that. It exists to prevent memory unsafety—dangling references, double frees. Once you reframe it that way, most of its decisions stop looking arbitrary.

The method also must be honest about one class of errors. Rust's borrow checker is a sound but incomplete analysis: it rejects some programs that are perfectly safe, because its model of aliasing is deliberately conservative. These cases are not deductible from the ownership rules. The famous example: borrowing two distinct array elements as mutable at once. The compiler refuses, and the canonical safe workaround is a function you would never guess exists. For this narrow class—and only this class—questioning is the wrong pedagogy. The right move is explicit instruction: "this is a limitation of the analyzer, not your error. Here is the canonical pattern." Knowing when to stop being Socratic is part of the method.

Measuring Progress

The final piece is measurement, because without it, the fluency illusion creeps back in. Two instruments matter.

Calibration. Every time you answer, record a confidence. If you answer correctly 80 percent of the time but claimed 95 percent confidence, you are overconfident—a signal to go back. Confidence should track accuracy. This single habit destroys illusions of competence, because it forces you to admit when you were guessing.

Spaced mastery. A concept is not "learned" because you understood it once. The research on delayed judgments is unambiguous: judgments made right after study are poor predictors; the same judgment made after a delay predicts future performance far better. So a concept becomes solid only after several successful recalls, spread over time (roughly a day, a week, a month), where each success required a correct explanation—not just a correct answer. A correct answer with a wrong justification does not count; it is the signature of the illusion.

Track every concept through four states: untouched, shaky, solid, and misconception (a diagnosed wrong model that needs explicit correction, not mere review). Rust has few concepts but a long dependency chain, so it rewards this discipline more than most languages.

Conclusion

AI is the best thing that ever happened to learning a programming language—if you use it as an opponent instead of a shortcut. The research predicts the shortcut's failure mode precisely: effortless progress in the moment, empty retention later.

The counter-protocol is simple to state and hard to follow: the AI never writes code; you must describe the memory state before anything is validated; names are given only after concepts are earned; errors are analyzed, not fixed; and progress is measured by spaced, justified recall. Rust, with its ruthless dependency chain, punishes every faked understanding—which makes it the best possible training ground.

The friction is not the obstacle. The friction is the product.

Try it this week: pick one Rust concept, forbid the AI from showing you a single line of code, and force yourself to describe the memory state before asking for anything. The session will feel slower. The learning will be real.

Sources