Why it matters: AI tools write confident, clean code against the type they can see, but in object-oriented systems the type that actually runs at execution time can be a completely different subclass, and that gap produces bugs that pass every test and still fail in production.
The Details:
A single method call like order.save() looks trivial, yet at runtime it might resolve to a subclass that skips an audit log or triggers an entirely different flow. The assistant reads the base class definition in its context window, follows the declared type, and writes code that is locally correct and globally wrong because it never opened the override that actually fires.
Scale turns an old mistake into a systemic one. A distracted engineer misses one override; an AI session can generate dozens of call sites in minutes, each carrying the identical blind spot, each dressed in fluent syntax that discourages the scrutiny it actually needs. Polished output becomes a kind of camouflage that pulls reviewer attention away from the riskiest lines.
Dynamic dispatch makes this worse. When a factory, registry, or feature flag selects the real implementation at runtime, the model is reasoning about a silhouette defined by an interface, not an object with a known type. If nobody feeds it the list of concrete implementations, it writes confidently to the interface and misses whatever configuration actually decides behavior.
The fix sits upstream of the code, not in review. Searching for every definition of a method and pasting the results into the prompt, or maintaining a short, visible inventory of registered strategies and tenant overrides, gives the tool the actual dispatch surface to reason from instead of a single declared type.
Bottom Line: An AI assistant is only as accurate as the dispatch map you hand it before it writes a single line.
Enjoy this article?
Listen to the Claude Code Conversations radio show or join the community.