How To Automatically Split Temporary Variables in Delphi

This article discusses proper usage of temporary variables, motivations for splitting improper variables, and how to use Castalia to automatically split them.

I would like to address a question that I get frequently from people who are seeing Castalia for the first time.  When they look at the refactorings, they see things like "Extract Method" and "Rename Local Variable," which are pretty self-explanatory.  That is, you can figure out what they do based on the name.  Then they see "Split Temporary Variable" and they're not sure what to think.  It's not a very intuitive refactoring, and for the most part, it gets ignored, despite being incredibly useful.

In a nutshell, this refactoring is used when "you have a local variable that is assigned more than once, and is not a loop variable nor a collecting variable" (Martin Fowler in Refactoring: Improving the Design of Existing Code).

There are lots of uses for local variables.  Some of these uses naturally require the variable to be assigned more than once.  For example, loop variables change each time around a loop (such as I in for I := 0 to 10).  Collecting temporary variables collect some value that is built up during a method, usually with a pattern that looks like "SomeVar := SomeVar + SomeNewValue."

Other temporary variables are used to hold the result of a piece of code for easy reference later.  These kind of variables ought to be set only once.  If they are set more than once, it's a clear sign that the variable has more than one responsibility in the function or procedure.  This is confusing to read and difficult to maintain, as it is hard to be sure at a given moment which responsibility is being fulfulled.  Each responsibility should be represented by a distinct variable, making the code easier to read and maintain.

This is where the "Split Temporary Variable" refactoring comes in.  It will take a variable that has multiple responsibilities and split it into distinct variables that have unique responsibilities.  Let's work through an example:

 

 

procedure TForm1.UpdateCoordinates;

var

Temp: Integer;

begin

Temp := Shape1.Top;

StatusBar1.Panels[0].Text := IntToStr(Temp);

Temp := Shape1.Left;

StatusBar1.Panels[1].Text := IntToStr(Temp);

end;

 

In this method, the panels of a status bar are updated with the coordinates of a shape. The variable named "Temp" has multiple responsibilities within the method. It represents both the Top and the Left values. We can (and should) split these responsibilities.

To have Castalia perform this split, we place the cursor in the name of the variable to split (any reference to Temp will do, just click on it so the cursor is located within the word "Temp"). Choose "Split Temporary Variable" from the refactoring menu (either from the editor context menu or the main Edit menu). A dialog box appears telling us that we are going to split Temp, which is of type Integer, into two variables, and asks for the name of the new variable. We enter ShapeLeft as the new variable name and click OK.

Split Temporary Variable dialog box

After clicking OK, the refactoring explorer appears with the suggested changes. Notice that some of the changes are checked by default, others are not. Castalia assumes that the first responsibility of the variable is to remain with the existing variable, and the second responsibility is so be filled by the new variable. If you disagree with this assumption, you can check and uncheck these changes as you see fit.

We click "GO" (which has been renamed "Apply" in Castalia 2.2), and Castalia will make the selected changes. Now we have a procedure that looks like this:

 

procedure TForm1.UpdateCoordinates;

var

Temp, ShapeLeft: Integer;

begin

Temp := Shape1.Top;

StatusBar1.Panels[0].Text := IntToStr(Temp);

ShapeLeft := Shape1.Left;

StatusBar1.Panels[1].Text := IntToStr(ShapeLeft);

end;

This is improved. Of course, some additional refactoring could make this code even better. Using "Rename Local Variable" to rename Temp to something like ShapeTop would be a definite improvement. The code could be made even more concise by using "Inline Temporary Variable" to eliminate the variables entirely.

In this article, we have learned about appropriate usage of temporary variables and how to use Castalia's "Split Temporary Variable" refactoring to improve those areas where we may have improperly used them. More information about Castalia's other refactorings can be found here.

 

Share this article!

Follow us!

Find more helpful articles: