/  10
 
Refactoring Erlang Programs
Huiqing Li, Simon ThompsonUniversity of Kent, UKL´aszl´o L¨ovei, Zolt´an Horv´ath, Tam´as Kozsik, Anik ´o V´ıg, Tam´as Nagy E¨otv¨os Lor´and University, Hungary
Abstract
We describe refactoring for Erlang programs, and work in progress to build two tools to give machine supportfor refactoring systems written in Erlang. We commenton some of the peculiarities of refactoring Erlang pro-grams, and describe in some detail a number of refac-torings characteristic of Erlang.
1. Introduction
Refactoring [6] is the process of improving the de-sign of a program without changing its external be-haviour. Behaviour preservation guarantees that refac-toring does not introduce (or remove) any bugs. Sep-arating general software updates into functionalitychanges and refactorings has well-known benefits.While it is possible to refactor a program by hand, toolsupport is invaluable as it is more reliable and allowsrefactorings to be done (and undone) easily. Refactor-ing tools can ensure the validity of refactoring steps byautomating both the checking of the conditions for therefactoring and the refactoring transformation itself,making the process less painful and error-prone.Refactoring has been applied to a number of lan-guages and paradigms, but most of the work in build-ing tools has concentrated on object-oriented program-ming. In this paper we report on work in progress at ouruniversities to build tools to support the refactoring of Erlang programs.The paper begins with a brief introduction to refac-toring, which is followed by a discussion of the partic-ular question of refactoring Erlang systems. We then
Supported by EPSRC in the UK, GVOP-3.2.2-2004-07-0005/3.0ELTE IKKK, Ericsson Hungary, Bolyai Research Fellowship andELTE CNL in Hungary
describe the approaches taken by our two teams: in anutshell, the Kent team work over a enriched abstractsyntax tree (AST), whereas the research at E¨otv¨osLor´and University builds the representation in a re-lational database.After describing the systems we speculate on whatrefactorings are the most appropriate to Erlang and aremost useful to the working Erlang programmer, beforeconcluding and surveying future work for both teams.
2. Refactoring
Refactorings transform the structure of a program without changing its functionality. They are characterisedby being
diffuse
and
bureaucratic
. They ate diffuse inthe sense that a typical refactoring will affect the wholeof a module or set of modules, rather than a single def-inition in a program, which is often the case for a pro-gram optimising transformation. They are bureaucraticin that they require attention to detail; for instance, tak-ing into account the binding structure of a program.Refactorings are not simply syntactic. In order topreserve the functionality of a program, refactorings re-quire awareness of various aspects of the semantics of the program including types and module structure andmost importantly the
static semantics
of the program:that is the scope of definitions, the binding structureof the program (the association between the use of anidentifier and its definition), the uniqueness of defini-tions and so forth.Each refactoring comes with a set of side conditions,which embody when a refactoring can be applied toa program without changing its meaning. Our experi-ence of building refactoring tools so far shows that formost refactorings, the side-condition analysis is morecomplex than the program transformation part. Taking
 
a concrete example, the general side conditions for re-naming an identifier could be as follows.
The existing binding structure should not be af- fected. No binding for the new name may intervene be-tween the binding of the old name and any of its uses,since the renamed identifier would be captured by therenaming. Conversely, the binding to be renamed must not intervene between bindings and uses of the newname.
These side-conditions apply to most programminglanguages. However, each programming language mayalso impose its own particular constraints on this refac-toring. For example, in an Erlang program using theOTP library, a user should not rename certain functionsexported by a call-back module. For some languages,refactoring conditions can be checked at compile time;the more dynamic nature of Erlang means that somenecessary conditions can only decided at run-time; wereturn to this point below.
2.1 Tool Support for Refactorings
Although it is possible to refactor a program manu-ally, it would be both tedious and error-prone to refac-tor large programs this way. Interactive tool support forrefactoring is therefore necessary, as it allows refactor-ings to be performed easily and reliably and to be un-done equally easily.A refactoring tool needs to get access to both thesyntactic and static semantic information of the pro-gram under refactoring. While detailed implementationtechniques might be different, most refactoring tools gothrough the following process: first transform the pro-gram source to some internal representation, such asan abstract syntax tree (AST) or database table; thenanalyse the program to extract the necessary static se-mantic information, such as the binding structure of theprogram, type information and so forth.After that, program analysis is carried out based onthe internal representation of the program and the staticsemanticsinformationtovalidatetheside-conditionsof the refactoring. If the side-conditions are not satisfied,the refactoring process stops and the original programis unchanged, otherwise the internal representation of the program is transformed according to the refactor-ing. Finally, the transformed representation of the pro-gram need to be presented to the programmer in pro-gram source form, with comments and the original pro-gram appearance preserved as much as possible.
-module (sample).-export([printList/1]).printList([H|T]) ->io:format("~p\n", [H]),printList(T);printList([]) -> true.
Figure 1.
The initial program
-module (sample).-export([printList/1, broadcast/1]).printList([H|T]) ->io:format("~p\n", [H]),printList(T);printList([]) -> true.broadcast([H|T]) ->H ! "The message",broadcast(T);broadcast([]) -> true.
Figure 2.
Adding a new function na¨ıvelyThe Kent group are responsible for the project‘Refactoring Functional Programs’ [7], which has de-veloped the Haskell Refactorer, HaRe [9], providingsupport for refactoring Haskell programs. HaRe is amature tool covering the full Haskell 98 standard, in-cluding “notoriously nasty” features such as monads,and is integrated with the two most popular develop-ment environments for Haskell programs: Vim and(X)Emacs. HaRe refactorings apply equally well tosingle- and multiple-module projects. HaRe is itself implemented in Haskell.Haskell layout style tends to be idiomatic and per-sonal, especially when a standard layout is not enforcedby the program editor, and so needs to be preservedas much as possible by refactorings. HaRe does this,and also retains comments, so that users can recognisetheirsourcecodeafterarefactoring.Thecurrentreleaseof HaRe supports 24 refactorings, and also exposes anAPI [10] for defining Haskell refactorings and programtransformations.
3. Refactoring Erlang Programs
Figures1-5illustrate how refactoring techniques can be used in the Erlang program development process.
 
-module (sample).-export([printList/1]).printList(L) ->printList(fun(H) ->io:format("~p\n", [H]) end, L).printList(F,[H|T]) ->F(H),printList(F, T);printList(F,[]) -> true.
Figure 3.
The program after generalisation
-module (sample).-export([printList/1]).printList(L) ->forEach(fun(H) ->io:format("~p\n", [H]) end, L).forEach(F,[H|T]) ->F(H),forEach(F, T);forEach(F,[]) -> true.
Figure 4.
The program after renamingThe example presented here is small-scale, but it ischosen to illustrate aspects of refactoring which canscale to larger programs and multi-module systems.In Figure1,the function
printList/1
has beendefined to print all elements of a list to the standardoutput. Next, suppose the user would like to defineanother function,
broadcast/1
, which broadcasts amessage to a list of processes.
broadcast/1
has avery similar structure to
printList/1
, as they bothiterate over a list doing something to each element inthe list. Na¨ıvely, the new function could be added bycopy, paste, and modification as shown in Figure2.However, a
refactor then modify
strategy, as shown inFigures3-5, would make the resulting code easier to maintain and reuse.Figure3shows the result of generalising the func-tion
printList
on the sub-expression
io:format("~p/n",~[H])
The expression contains the variable
H
, which is onlyin scope within the body of 
printList
. Instead of generalising over the expression itself, the transforma-
-module (sample).-export([printList/1, broadcast/1]).printList(L) ->forEach(fun(H) ->io:format("~p\n", [H]) end, L).broadcast(Pids)->forEach(fun(H) ->H ! "The message" end, Pids).forEach(F,[H|T]) ->F(H),forEach(F, T);forEach(F,[]) -> true.
Figure 5.
The program after adding a functiontion is achieved by first abstracting over the free vari-able
H
, and by making the generalised parameter a
 function
F
. In the body of 
printList
the expression
io:format("~p/n", H])
has been replaced with
F
applied to the local variable
H
.The arity of the
printList
has thus changed; in or-der to preserve the interface of the module, we create anewfunction,
printList/1
,asanapplicationinstanceof 
printList/2
with the first parameter supplied withthe function expression:
fun(H) -> io:format("~p/n", [H]) end
.Note that this transformation gives
printList
a func-tional argument, thus making it a characteristically‘functional’ refactoring.Figure4shows the result of renaming
printList/2
to
forEach/2
. The new function name reflects thefunctionality of the function more precisely. In Figure5,function
braodcast/1
is added as another applica-tion instance of 
forEach/2
.Refactorings to generalise a function definition andto rename an identifier are typical structural refactor-ings, implemented in our work on both Haskell and Er-lang.
3.1 Language Issues
In working with Erlang we have been able to com-pare our experience with what we have done in writ-ing refactorings for Haskell. Erlang is a smaller lan-guage than Haskell, and in its pure functional part, verystraightforward to use. It does however have a number

Share & Embed

More from this user

Add a Comment

Characters: ...