Towards Trustworthy Refactoring in Erlang
Tool-assisted refactoring transformations must be trustworthy if programmers are to be confident in applying them on arbitrarily extensive and complex code in order to improve style or efficiency. We propose a simple, high-level but rigorous, notation for defining refactoring transformations in Erlang, and show that this notation provides an extensible, verifiable and executable specification language for refactoring. To demonstrate the applicability of our approach, we show how to define and verify a number of example refactorings in the system.
💡 Research Summary
The paper addresses the problem of trustworthiness in automated refactoring tools for Erlang, arguing that developers need strong guarantees that refactorings preserve program semantics before they can safely apply such tools to large and complex code bases. The authors propose a high‑level, yet rigorously defined, domain‑specific language (DSL) for specifying refactoring transformations. This DSL is tightly coupled with a semantic program graph representation, an extension of the abstract syntax tree that annotates each node with static semantic information such as function purity, arity, module membership, and call‑site relationships. By operating on this enriched graph, the DSL can express transformations using concrete Erlang syntax, meta‑variables, and list meta‑variables, while side‑conditions are expressed through built‑in semantic functions and predicates (e.g., fresh/1, atom/1, module/1).
A refactoring is defined as a conditional rewrite rule consisting of a matching pattern, a replacement pattern, and a WHEN clause that encodes the side‑conditions. The language is intentionally representation‑independent: developers write rules in terms of language concepts rather than low‑level AST nodes, which improves readability and reduces the chance of errors. The DSL supports three categories of refactorings: (1) prime local refactorings, which are single‑rule transformations affecting a single syntactic subtree; (2) prime extensive refactorings, which combine multiple rewrite rules to achieve a larger effect; and (3) composite refactorings, built by sequencing already verified prime refactorings. To aid the definition of extensive transformations, the authors introduce “refactoring schemes” that capture common patterns and can be instantiated with concrete rules, provided they satisfy certain verification constraints.
Verification is performed by translating each rewrite rule and its side‑conditions into first‑order logic formulas. The matching logic captures the structural equivalence of the pattern and replacement, while the semantic predicates are given precise logical definitions. An automated prover checks that, under the given conditions, the transformation preserves the semantics of the program fragment. If static verification fails—due to incomplete semantic information or undecidable conditions—the framework falls back to dynamic validation using test suites, ensuring a pragmatic safety net.
The paper demonstrates the approach with several examples. The “extract list head” refactoring shows a local transformation that introduces a fresh variable to simplify a compound list‑head expression. The “add module qualifier” example illustrates an extensive transformation that rewrites module‑local function calls into fully qualified calls, handling an arbitrary number of arguments via list meta‑variables. Composite refactorings are constructed by chaining these primitives, and the authors show how the DSL’s implicit THIS parameter (the focus node) and node selectors simplify the specification of the transformation scope.
Related work is surveyed, highlighting that most prior efforts either operate directly on low‑level ASTs, lack a systematic verification pipeline, or target generic languages rather than a specific one. By focusing on Erlang, the authors can embed language‑specific knowledge (e.g., dynamic typing, concurrency primitives) into the DSL, making specifications both concise and expressive.
In conclusion, the authors claim that their DSL, together with the semantic program graph and automated verification, provides a practical path toward trustworthy, large‑scale refactoring in Erlang. Future directions include extending the approach to handle more complex concurrency refactorings, improving the underlying static analysis for richer semantic predicates, and exploring applicability to other functional languages. The work represents a significant step in bridging the gap between high‑level, developer‑friendly refactoring specifications and formal guarantees of behavior preservation.
Comments & Academic Discussion
Loading comments...
Leave a Comment