Files
codeql/java/ql/src/Language Abuse/ChainedInstanceof.qhelp
2018-08-30 10:48:05 +01:00

84 lines
3.7 KiB
XML

<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>
Long sequences of type tests are often used to dispatch control to different branches of the code based on the type
of a variable, as shown in the example below. They are often used to simulate pattern-matching in languages that do
not support it. Whilst this works as a dispatch method, there are a number of problems:
</p>
<ul>
<li>
They are difficult to maintain. It is easy to add a new subtype and forget to modify all of the type test sequences
throughout your code.
</li>
<li>
They introduce unwanted dependencies on concrete classes. Code cannot be written only in terms of an interface but
must instead be written considering all of the different special cases.
</li>
<li>
They can be error-prone - it is easy to test for a base type before a derived type, resulting in a failure to
execute the code handling the derived type.
</li>
</ul>
</overview>
<recommendation>
<p>
There are a number of different possible solutions to this problem:
</p>
<ul>
<li>
<strong>Polymorphism</strong>. You can add a virtual method to the type hierarchy and put the segments of code to be called
in the relevant override for each concrete class. This is a good solution when: (a) you can change the type hierarchy
and (b) the operation being implemented is core functionality that the types should implement. If you implement this
solution then you must be careful not to introduce unwanted dependencies. If the operation depends on entities
that themselves depend on the type hierarchy, then you cannot move the operation to the type hierarchy without creating a dependency cycle.
</li>
<li>
<strong>The visitor pattern</strong>. You can introduce a visitor interface containing a visit method for each type in
the type hierarchy, and add an <code>accept</code> method to each type in the hierarchy that takes a visitor as its parameter.
The <code>accept</code> method calls the visit method of the visitor on <code>this</code>. Concrete visitors then implement the
interface and process each specific type as necessary. This is a good solution when: (a) you can change the type hierarchy
and (b) the type hierarchy should not know about the operation being implemented (either to avoid dependency
or because it is not core functionality for the types in the hierarchy). It is also useful when you want to provide
multiple operations with the same structure, on the same set of types, and you want the types themselves to control the way
that the operation is structured. For example, "visit this tree using an in-order walk and apply the operation to each
node". The basic visitor pattern is not suitable for all situations because it is cyclically-dependent, and the infrastructure involved
is comparatively heavyweight.
</li>
<li>
<strong>Reflection</strong>. You can look up one of a set of overloaded methods based on the type of one of the method
parameters and invoke the method manually. This results in a loss of
type safety and is rather untidy, but there are times when it is the best solution. In particular, reflection is useful when you
cannot change the type hierarchy, for example, because it is third-party code.
</li>
</ul>
</recommendation>
<example>
<p>The following example demonstrates the use "Polymorphism" and "The visitor pattern". More details on reflection can be found in [Flanagan].</p>
<sample src="ChainedInstanceof.java" />
</example>
<references>
<li>D. Flanagan, <em>Java in a Nutshell: A Desktop Quick Reference</em>.
O'Reilly Media, 1997.</li>
<li>E. Gamma, R. Helm, R. Johnson, J. Vlissides, <em>Design patterns: elements of reusable
object-oriented software</em>. Addison-Wesley Longman Publishing Co., Inc. Boston, MA, 1995.</li>
</references>
</qhelp>