wiki:RefactoringSteps/MoveFunction

Version 2 (modified by manualwiki, 13 years ago) (diff)

--

Move function

Modules contain functions which consist of one or more clauses. Moving functions between modules is a possible refactoring step. This transformation must move each clauses of the given functions from the source module to the target module and have to compensate every reference of functions and of entities used by the functions. The move function refactoring is useful in module clustering, there it is needed to split the library modules into parts that are determined by the clusters.

Move function example:

%%from.erl

-module(from).

-export([print/1,pzip/1]).

print(Pairs) ->
   io:format(
      "~p~n",
      pzip(Pairs)).

pzip([A,B|Rest]) ->
   [{A,B}|pzip(Rest)];
pzip(_) ->
   [].
%%xlists.erl

-module(xlists).

-export([flatsort/1]).
 
flatsort(Xs) ->
   lists:usort(
      lists:flatten(Xs)).

Result:

%%from.erl

-module(from).

-export([print/1]).

print(Pairs) ->
   io:format(
      "~p~n",
      xlists:pzip(Pairs)).
%%xlists.erl

-module(xlists).

-export([flatsort/1]).
-export([pzip/1]).
 
flatsort(Xs) ->
   lists:usort(
      lists:flatten(Xs)).

pzip([A,B|Rest]) ->
   [{A,B}|pzip(Rest)];
pzip(_) ->
   [].

Side conditions

  • The names of the selected functions should not conflict with other functions in the target module, neither with those imported from another module (overloading). Furthermore, the name should be a legal function name in all modules.
  • If the user do not select functions to be moved, the transformation starts an interaction. The tool gives a checkbox list to the user to select the functions to be moved.
  • Macro name conflicts must not occur in the target module, that is, macro names used in the functions must refer to the same macro definition in the source and in the target module. This applies to macros used in these macros too.
  • Record name conflicts must not occur in the target module, that is, record names used in the functions must refer to the same record definition in the source and in the target module.

Transformation steps and compensations

  1. In the refactoring step the functions to be moved have to be marked either at the definition or in the export list. A list has to be created from the function name and arity pairs. Duplicity should be avoided and only real function names and arities should occur in the list.
  1. The new place of the functions, or the target module, has to be asked from the user. If there is no such module in the tool database, it has to be loaded.
  1. If the transformation does not disobey the rules, the functions have to be deleted from their original places together with all their clauses.
  1. The moved functions have to be placed to the end of the new module.
  1. Functions have to be deleted if they appear in the export list of the original module. (If they were exported, they have to be exported in their new place, too.)
  1. The functions, which are called in the moved function but remain in the original module, have to be put in an export list in the original module.
  1. If the functions to be moved are called in other functions from the original module, they have to be exported in the new module and the calls in the original module have to be changed to qualified calls.
  1. If the moved functions are referred to by qualified names, the module names have to be changed to the new module name.
  1. After the transformation the module names in the import lists have to be changed to the name of the target module.
  1. The moved function in the target module has to be deleted from the import list.
  1. Records and macros used in the moved function have to be made visible in the target module, either by moving them into header files (or including the header file if the definition is already in one), or copying their definition.