4.

About This Bug Pattern

This bug pattern results from using special fields inside classes to distinguish conceptually distinct subtypes. Because these subtypes are grouped together in the same class, static type checking is unable to catch a misuse of data that could have been caught if the subtypes were split into separate classes.

The Symptoms

One common symptom of an Impostor Type bug is that many conceptually distinct types of data are all treated in the same (and incorrect) manner when the program is run. Another common symptom is that data doesn't match any of the designated types.

As a rule of thumb, suspect this bug pattern whenever there is a mismatch between the conceptual type of data and the way it is handled by your program.

Note 

Common symptoms include conceptually distinct types of data being treated in the same manner and data not matching any of the designated types.

To illustrate how easily bugs of this pattern can be introduced, let's consider a simple example. Suppose we want to manipulate various Euclidean forms, such as circles, squares, and so on. These forms will have no position, but they will have a scale, so that it will be possible to compute their area.

Listing 15-1: Implementation of Shapes with Impostor Types

start example
 public class Form {   String shape;   double scale;   public Form(String _shape, double _scale) {     this.shape = _shape;     this.scale = _scale;   }   public double getArea() {     if (shape.equals("square")) {       return scale * scale;     }     else if (shape.equals("circle")) {       return Math.PI * scale * scale;       130   }   else { // shape.equals("triangle"), an equilateral triangle   return scale * (scale * Math.sqrt(3) / 4);   }  } } 
end example

There are serious disadvantages to implementing a data type in this way, even though you see it done often. One of the most glaring drawbacks is that this method is not very extensible. If we wanted to introduce a new shape for our forms (such as "pentagon"), we'd have to go in and modify the source code for the getArea() method. But extensibility is a separate concern; how does this programming style increase our susceptibility to errors?

Consider what would happen if, in some other part of the program, we constructed a new Form object as follows:

Listing 15-2: Constructing a New Form

start example
   Form f = new Form("sqaure", 2); 
end example

The form "square" has been misspelled. But as far as the compiler is concerned, this is perfectly valid code.

Now consider what will happen when we try to call getArea() on our new Form object. Because the shape of the Form won't match any of the tests in the if- then-else block, its area will be computed in the else clause, as if it were a triangle!

There will be no error signaled. Indeed, in many circumstances, the return value will appear to be a perfectly reasonable number. Even if we put in some redundancy and check that the implied condition in the else clause holds (with an assertion, for instance), the error won't be found until the code is run.

Many other similar bugs might occur with the previous code. A clause might be accidentally left out of the if-then-else block, causing all Forms of the type corresponding to that clause to be handled improperly. Additionally, because the impostor type is just a String in a field, it might be modified, either accidentally or maliciously. Either way, such modifications could wreak all sorts of havoc.

The Cause

Again, the program uses fields with tags in lieu of separate classes for the various types of data.

Cures and Preventions

As you might have guessed, I suggest avoiding bugs of this type by using the type system to weed them out during static checking. Consider this alternative implementation:

Now consider what would happen if we were to mistype Square as Sqaure when creating a new Form. The compiler would signal an error, telling us that class Sqaure could not be found. The errant code would never even have a chance to run.

Similarly, the compiler would not allow us to forget to define getArea() for any of our subclasses. And, of course, it would be impossible for any object to change the type of a Form.



Bug Patterns in Java
Bug Patterns In Java
ISBN: 1590590619
EAN: 2147483647
Year: N/A
Pages: 95
Authors: Eric Allen

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net