Depth of Type in Inheritance Hierarchy

The depth of a type is the length of a longest path in the inheritance hierarchy from Object to the type.

The depth of a type is an indication of how deeply nested a type is in a given design. Very deep types can be an indication of over-engineering, whereas a system with predominantly shallow types may not be exploiting object-orientation to the full.

This metric is often confused with Number of Ancestors in Inheritance Hierarchy, which counts all the ancestors, not just those on the longest path to Object.

The depth metric is used to compute the Specialization Index, which is a measure of the extent to which subclasses override behavior in super classes.

Pre-packaged Query

Query name = "Semmle/Metrics/Types/Inheritance/RefTypes that are deep in the type hierarchy"

Reports reference types whose maximum distance to Object is greater than 6, in decreasing order of distance, as a bar chart.

from MetricRefType t, int d
where t.fromSource() and d = t.getInheritanceDepth() and d > 6
select t, d order by d desc

.QL Source of Metric

This metric is defined in the class MetricRefType. We first compute the length of some path to the root, non-deterministically. Next, we take the maximum over all those lengths, to obtain the depth.

   // find the length of *some* path to the root of the hierarchy 
   int getADepth() {
       (this.hasQualifiedName("java.lang", "Object") and result=0)
       or
       (result = ((MetricRefType)this.getASupertype()).getADepth() + 1)
   }

   // compute depth of inheritance metric
   int getInheritanceDepth() {
       result = max(this.getADepth())
   }

Note how the result of a getASupertype() is cast to MetricRefType, so that the getADepth() method can be called on it. To Java programmers, this may appear strange at first, but remember that .QL classes are characterized by logical properties: casting to a type is just checking that the value satisfies the property of being a MetricRefType. In this example, since any RefType is also a MetricRefType, that check will always succeed.

Variation

Spinellis defines this metric subtly differently, only counting classes, not interfaces. To get Spinellis's definition, we can override the above as follows:

class MyMetricRefType extends MetricRefType {

  RefType getSuperClass() {
    result = this.getASupertype()
  }

  int getADepth() {
       (this.hasQualifiedName("java.lang", "Object") and result=0)
       or
       (result = ((MyMetricRefType)this.getSuperClass()).getADepth() + 1)
   }
} 

References

Shyam R. Chidamber and Chris F. Kemerer. A Metrics Suite for Object Oriented Design . IEEE Transactions on Software Engineering, 20(6), pages 476-493, June 1994.

Diomides D. Spinnelis. Code Quality: The Open Source Perspective. Addison-Wesley 2007.

Diomides D. Spinnelis. ckjm - Chidamber and Kemerer Java Metrics. (implementation of CK metrics), 2006.

Digg!Reddit!Del.icio.us!Facebook!Slashdot!Technorati!StumbleUpon!Ma.gnolia!

Comments
Only registered users can write comments!
jeanHelou - Interfaces IP:195.212.29.xxx | 10/05/2007 16:04:00
Quote:

This metric is often confused with Number of Ancestors in Inheritance Hierarchy, which counts all the ancestors, not just those on the longest path to Object.

If I understand right and for the Java language, the depth of type will only count classes not interfaces. The Number of ancestors on the other hand will follow the full inheritance tree for both interfaces and classes.
 
< Prev   Next >