Renaming Without Breaking Anything
Open any well-written program and the names carry half the meaning: total, retries, is_admin, price_with_tax. The machine ignores every one of them. To the interpreter, total and _0xa are the same variable, as long as every mention of it uses the same spelling. That gap between what names mean to humans and what they mean to machines is where the rename transformation lives.
Think of a name like a label on a moving box. The movers do not care whether the box says KITCHEN or BOX 7, they care that the same label is on the box every time they look for it. Renaming swaps every label for a new one, on the box and on every list that mentions the box, all at once. Nothing inside any box changes.
Renaming is the simplest interesting transformation because it is pure relabeling. The program's structure, its control flow, its data flow, every computation, all stay identical. Only the identifiers change. That makes it the perfect first pass to study: if you understand what it takes to do this one safely, you understand the discipline behind every heavier transform.
The guarantees a rename pass must keep
- Consistency: a variable's definition and every one of its uses must get the same new name. Miss one use and the program reads an undefined variable.
- No collisions: two different variables must never be renamed to the same name in the same scope, or they silently merge into one and the program computes garbage.
- Nothing but names: string contents, keywords, and numbers must be untouched. The word total inside a printed label is data, not a variable.
- Scope awareness: in real languages, the same spelling can mean different variables in different scopes. A correct pass renames each variable, not each spelling.
Every one of those guarantees is easy on a syntax tree and treacherous on raw text. The tree knows which nodes are variables, which scope each one belongs to, and which string characters are just data. A text find-and-replace knows none of that. This is the deep reason rename passes are built on parsers, exactly the machinery you met in Level 3.
Watch a rename pass work
Drag the slider to rename one variable at a time. Watch how each change updates the definition and every use together, and how the string label in the print statement is never touched.
Notice what survives. The arithmetic is fully readable, the control flow is unchanged, the output is identical. Renaming removes exactly one thing: the free documentation. That is why, on its own, it is a mild protection. It slows a reader down without stopping one, and later levels are honest about that.
Where naive renaming goes wrong
The classic failure is renaming with text search instead of tree edits. Search for total, replace with _0xa, and you also rewrite the word total inside a printed message, a comment, or a longer name like subtotal. The program either breaks loudly or, far worse, keeps running and prints the wrong thing.
Compiler literature calls the deeper version of this problem capture. If a pass renames an inner variable to a name that an enclosing scope already uses, the inner uses can suddenly refer to the outer variable, silently changing behaviour while every individual edit looked reasonable. Production renamers avoid it by generating names from a reserved namespace no source program uses, and by tracking a symbol table that maps each variable identity, not each spelling, to its new name. The rule generalises: a transform must operate on the program's structure and identity, never on its surface text.
The same defect class has shipped in real tools in every language. Any transform written as a regex over source text will eventually rewrite something inside a string literal or a comment, because regular expressions do not know where a string ends. Tree in, tree out is not a style preference. It is the only way the guarantees hold.
Repair a botched rename
Someone renamed this program with careless text replace. The variables are fine, but the replacement also hit the label inside the string, so the output reads wrong. Fix the string so the program prints its label correctly again. The variables can stay ugly, they work.
Who runs this pass
- Your editor: rename symbol in an IDE is exactly this transform, pointed at making names better instead of worse.
- Minifiers: JavaScript shipped to browsers is routinely renamed to single letters to save bytes, with no protective intent at all.
- Compilers: many compiled languages discard source names entirely on the way to machine code.
- Obfuscators: the same pass with hostile naming, chosen to give a reader nothing to hold on to.
Renaming is pure relabeling: same structure, same behaviour, no names. Doing it safely demands tree-based edits, consistent per-variable maps, and absolute respect for string boundaries. It removes the free documentation and nothing else, which makes it a foundation layer for obfuscation, never the whole defense.
Frequently asked questions
Is renaming reversible?
The mechanical part is not, because the original names are simply gone from the output. But a patient reader, or modern tooling, can re-derive good names by studying what each variable does and relabeling it, so renaming should be understood as removing a convenience, not as encryption.
Why do renamed programs still contain readable strings and keywords?
Because renaming only targets identifiers. Keywords belong to the language and must survive for the program to parse, and strings are data the program needs at runtime. Hiding strings is a different transform with its own lesson in Level 6.