Refactoring Erlang Programs Huiqing Li Simon Thompson University

  • Slides: 63
Download presentation
Refactoring Erlang Programs Huiqing Li Simon Thompson University of Kent

Refactoring Erlang Programs Huiqing Li Simon Thompson University of Kent

Overview What is refactoring? Examples The process of refactoring Tool building and infrastructure What

Overview What is refactoring? Examples The process of refactoring Tool building and infrastructure What is in Wrangler … demo Latest advances: data, processes, erlide.

Introducing refactoring

Introducing refactoring

Soft-ware There’s no single correct design … … different options for different situations. Maintain

Soft-ware There’s no single correct design … … different options for different situations. Maintain flexibility as the system evolves.

Refactoring means changing the design or structure of a program … without changing its

Refactoring means changing the design or structure of a program … without changing its behaviour. Modify Refactor

Examples

Examples

Generalisation and renaming -module (test). -export([f/1]). add_one ([H|T]) -> [H+1 | add_one(T)]; -module (test).

Generalisation and renaming -module (test). -export([f/1]). add_one ([H|T]) -> [H+1 | add_one(T)]; -module (test). -export([f/1]). add_one (N, [H|T]) -> add_int (N, [H|T]) -> [H+N | add_one(N, T)]; [H+N | add_int(N, T)]; add_one ([]) -> []. add_one (N, []) -> []. add_int (N, []) -> []. f(X) -> add_one(X). f(X) -> add_one(1, X). f(X) -> add_int(1, X).

Generalisation -export([print. List/1]). -export([print. List/2]). print. List([H|T]) -> io: format("~pn", [H]), print. List(T); print.

Generalisation -export([print. List/1]). -export([print. List/2]). print. List([H|T]) -> io: format("~pn", [H]), print. List(T); print. List([]) -> true. print. List(F, [H|T]) -> F(H), print. List(F, T); print. List(F, []) -> true. print. List([1, 2, 3]) print. List( fun(H) -> io: format("~pn", [H]) end, [1, 2, 3]).

Generalisation -export([print. List/1]). print. List([H|T]) -> io: format("~pn", [H]), print. List(T); print. List([]) ->

Generalisation -export([print. List/1]). print. List([H|T]) -> io: format("~pn", [H]), print. List(T); print. List([]) -> true. print. List(F, [H|T]) -> F(H), print. List(F, T); print. List(F, []) -> true. print. List(L) -> print. List( fun(H) -> io: format("~pn", [H]) end, L).

Asynchronous to synchronous pid! {self(), msg}, receive {pid, ok}-> ok {Parent, msg} -> body

Asynchronous to synchronous pid! {self(), msg}, receive {pid, ok}-> ok {Parent, msg} -> body {Parent, msg} -> Parent! {self(), ok}, body

Refactoring

Refactoring

Refactoring = Transformation + Condition Transformation Condition Ensure change at all those points needed.

Refactoring = Transformation + Condition Transformation Condition Ensure change at all those points needed. Is the refactoring applicable? Ensure change at only Will it preserve those points needed. semantics of the module? the program?

Transformations full stop one

Transformations full stop one

Condition > Transformation Renaming an identifier "The existing binding structure should not be affected.

Condition > Transformation Renaming an identifier "The existing binding structure should not be affected. No binding for the new name may intervene between the binding of the old name and any of its uses, since the renamed identifier would be captured by the renaming. Conversely, the binding to be renamed must not intervene between bindings and uses of the new name. "

Which refactoring exactly? Generalise f by making 23 a parameter of f: f(X) ->

Which refactoring exactly? Generalise f by making 23 a parameter of f: f(X) -> Con = 23, g(X) + Con + 23. • This one occurrence? • All occurrences (in the body)? • Some of the occurrences … to be selected.

Compensate or crash? -export([old. Fun/1, new. Fun/1]). old. Fun(L) -> new. Fun(L) -> …

Compensate or crash? -export([old. Fun/1, new. Fun/1]). old. Fun(L) -> new. Fun(L) -> … …. -export([new. Fun/1]). or ? new. Fun(L) -> … ….

Refactoring tools

Refactoring tools

Tool support Bureaucratic and diffuse. Tedious and error prone. Semantics: scopes, types, modules, …

Tool support Bureaucratic and diffuse. Tedious and error prone. Semantics: scopes, types, modules, … Undo/redo Enhanced creativity

Semantic analysis Binding structure • Dynamic atom creation, multiple binding occurrences, pattern semantics etc.

Semantic analysis Binding structure • Dynamic atom creation, multiple binding occurrences, pattern semantics etc. Module structure and projects • No explicit projects for Erlang; cf Erlide / Emacs. Type and effect information • Need effect information for e. g. generalisation.

Erlang refactoring: challenges Multiple binding occurrences of variables. Indirect function call or function spawn:

Erlang refactoring: challenges Multiple binding occurrences of variables. Indirect function call or function spawn: apply (lists, rev, [[a, b, c]]) Multiple arities … multiple functions: rev/1 Concurrency Refactoring within a design library: OTP. Side-effects.

Static vs dynamic Aim to check conditions statically. Static analysis tools possible … but

Static vs dynamic Aim to check conditions statically. Static analysis tools possible … but some aspects intractable: e. g. dynamically manufactured atoms. Conservative vs liberal. Compensation?

Architecture of Wrangler

Architecture of Wrangler

Wrangler in Emacs

Wrangler in Emacs

Wrangler in Emacs

Wrangler in Emacs

Wrangler refactorings Rename variable/function/modu le Generalise function definition Move a function definition to another

Wrangler refactorings Rename variable/function/modu le Generalise function definition Move a function definition to another (new) module Function extraction Fold expression against function Expression search Detect duplicate code Tuple function parameters From tuple to record

Wrangler demo

Wrangler demo

Tool building

Tool building

Wrangler and Refactor. Erl Lightweight. Higher entry cost. Better integration with interactive tools (e.

Wrangler and Refactor. Erl Lightweight. Higher entry cost. Better integration with interactive tools (e. g. emacs). Better for a series of refactorings on a large project. Undo/redo external? Transaction support. Ease of implementing conditions. Ease of implementing transformations.

Integration … with IDEs Back to the future? Programmers' preference for emacs and gvim

Integration … with IDEs Back to the future? Programmers' preference for emacs and gvim … … though some IDE interest: Eclipse, Net. Beans … Issue of integration with multiple IDEs: building common interfaces.

Integration … with tools Test data sets and test generation. Makefiles, etc. Working with

Integration … with tools Test data sets and test generation. Makefiles, etc. Working with macros e. g. Quick. Check uses Erlang macros … … in a particular idiom.

APIs … programmer / user API in Erlang to support user-programmed refactorings: • declarative,

APIs … programmer / user API in Erlang to support user-programmed refactorings: • declarative, straightforward and complete • but relatively low-level. Higher-level combining forms? • OK for transformations, but need a separate condition language.

Verification and validation Possible to write formal proofs of correctness: • check conditions and

Verification and validation Possible to write formal proofs of correctness: • check conditions and transformations • different levels of abstraction • possibly-name binding substitution for renaming etc. • more abstract formulation for e. g. data type changes. Use of Quivq Quick. Check to verify refactorings in Wrangler.

Clone detection

Clone detection

The Wrangler Clone Detector Uses syntactic and static semantic information. Syntactically well-formed code fragments

The Wrangler Clone Detector Uses syntactic and static semantic information. Syntactically well-formed code fragments … identical after consistent renaming of variables, … with variations in literals, layout and comments. Integrated within the refactoring environment.

The Wrangler Clone Detector Make use of token stream and annotated AST. n Token–based

The Wrangler Clone Detector Make use of token stream and annotated AST. n Token–based approaches p Efficient. p Report non-syntactic clones. n AST-based approaches. p Report syntactic clones. p Checking for consistent renaming is easier.

The Wrangler Clone Detector Source Files Tokenisation Token Stream Normalisation Normalised Token Stream Suffix

The Wrangler Clone Detector Source Files Tokenisation Token Stream Normalisation Normalised Token Stream Suffix Tree Construction Suffix tree

The Wrangler Clone Detector Source Files Tokenisation Parsing + Static Analysis Token Stream Annotated

The Wrangler Clone Detector Source Files Tokenisation Parsing + Static Analysis Token Stream Annotated ASTs Normalisation Clone Decomposition Normalised Token Stream Suffix Tree Construction Suffix tree Filtered Initial Clones Clone Filter Initial Clones Clone Collector Syntactic Clones

The Wrangler Clone Detector Source Files Tokenisation Parsing + Static Analysis Token Stream Annotated

The Wrangler Clone Detector Source Files Tokenisation Parsing + Static Analysis Token Stream Annotated ASTs Normalisation Clone Decomposition Normalised Token Stream Suffix Tree Construction Suffix tree Filtered Initial Clones Clone Filter Initial Clones Clone Collector Syntactic Clones Consistent Renaming Checking Clones to report

The Wrangler Clone Detector Source Files Tokenisation Parsing + Static Analysis Token Stream Annotated

The Wrangler Clone Detector Source Files Tokenisation Parsing + Static Analysis Token Stream Annotated ASTs Normalisation Clone Decomposition Normalised Token Stream Suffix Tree Construction Filtered Initial Clones Syntactic Clones Consistent Renaming Checking Clones to report Clone Filter Formatting Suffix tree Initial Clones Clone Collector Reported Code Clones

Clone detection demo

Clone detection demo

Support for clone removal Refactorings to support clone removal. § Function extraction. § Generalise

Support for clone removal Refactorings to support clone removal. § Function extraction. § Generalise a function definition. § Fold against a function definition.

Case studies Applied the clone detector to Wrangler itself with threshold values of 30

Case studies Applied the clone detector to Wrangler itself with threshold values of 30 and 2. § 36 final clone classes were reported … 12 are across modules, and 3 are duplicated function definitions. § Without syntactic checking and consistent variable renaming checking, 191 would have been reported. Applied to third party code base (32 k loc, 89 modules), 109 clone classes reported.

Data-oriented refactorings

Data-oriented refactorings

Tupling parameters -module(tup 1). -export([gcd/2]). -module(tup 1). -export([gcd/1]). 2 gcd(X, Y) -> if X>Y

Tupling parameters -module(tup 1). -export([gcd/2]). -module(tup 1). -export([gcd/1]). 2 gcd(X, Y) -> if X>Y -> gcd(X-Y, Y); Y>X -> gcd(Y-X, X); true -> X end. gcd({X, Y}) -> if X>Y -> gcd({X-Y, Y}); Y>X -> gcd({Y-X, X}); true -> X end.

Introduce records … -module(rec 1). -record(rec, {f 1, f 2}). f 1 f 2

Introduce records … -module(rec 1). -record(rec, {f 1, f 2}). f 1 f 2 g({A, B})-> A + B. g(#rec{f 1=A, f 2=B})-> A + B. h(X, Y)-> g({X, X}), g(Y). h(X, Y)-> g(#rec{f 1=X, f 2=X}), g(#rec{ f 1=element(1, Y), f 2=element(2, Y)}).

Introduce records in a project Need to replace other expressions … • Replace tuples

Introduce records in a project Need to replace other expressions … • Replace tuples with record • Record update expression • Record access expression Chase dependencies across functions … … and across modules.

Refactoring and Concurrency

Refactoring and Concurrency

Wrangler and processes Refactorings which address processes • Register a process. • Rename a

Wrangler and processes Refactorings which address processes • Register a process. • Rename a registered process. • From function to process. • Add tags to messages sent / received.

Challenges to implementation Data gathering is a challenge because • Processes are syntactically implicit.

Challenges to implementation Data gathering is a challenge because • Processes are syntactically implicit. • Pid to process links are implicit. • Communication structure is implicit. • Side effects.

Underlying analysis Analyses include • Annotation of the AST, using call graph. • Forward

Underlying analysis Analyses include • Annotation of the AST, using call graph. • Forward program slicing. • Backwards program slicing.

Wrangler and Erlide

Wrangler and Erlide

Wrangler and Erlide is an Eclipse plugin for Erlang. • Distribution simplified. • Integration

Wrangler and Erlide is an Eclipse plugin for Erlang. • Distribution simplified. • Integration with the edit undo history. • Notion of project. • Refactoring API in the Eclipse LTK. Ongoing support for Erlide from Ericsson.

Issues on integration LTK has a fixed workflow for interactions. • New file vs

Issues on integration LTK has a fixed workflow for interactions. • New file vs set of diffs as representation. • Fold and generalise interaction pattern. • Cannot support rename / create file. Other refactorings involve search … a different API.

Conclusions

Conclusions

Future work Concurrency: continue work. Refactoring within a design library: OTP. Working with Erlang

Future work Concurrency: continue work. Refactoring within a design library: OTP. Working with Erlang Training and Consulting. Continue integration with Eclipse + other IDEs. Test and property refactoring in . Clone detection: fuller integration.

Ackonwledgements Wrangler development funded by EPSRC. The developers of syntax-tools, distel and Erlide. George

Ackonwledgements Wrangler development funded by EPSRC. The developers of syntax-tools, distel and Erlide. George Orosz and Melinda Toth. Zoltan Horvath and the Refactor. Erl group at Eotvos Lorand Univ. , Budapest.

http: //projects. cs. kent. ac. uk

http: //projects. cs. kent. ac. uk