Contents > 8 Defining Custom Design Metrics and Rules > 8.1 Definition of Metrics > 8.1.1 Projection > 8.1.1.8 Attribute "recurse"

8.1.1.8 Attribute "recurse"

With the "recurse" attribute, you can define metrics that take the transitive closure of relations or sets into account. The recurse attribute takes the values "true" or "false" (default).

Setting the value of "recurse" to true changes the meaning of a metric m for elements of type t as follows: in addition to processing the projection attributes as usual, apply metric m to all "compatible" elements in the projection, and add the result to the return value of the metric. An element is "compatible" if its type is t, or if its type is a subtype or supertype of t and metric m is defined for the type.

<metric name="NumCls_tc" domain="package"> 
  <description>The number of classes in a package, 
  its subpackages, and so on.</description>
  <projection relation="context" target="class" recurse="true"/>
</metric>
Without the "recurse" attribute being set to true, the above metric would just count the number of classes in a package. With recurse set to true, metric NumCls_tc is in addition recursively applied to all subpackages that are in the context of a package, and the values added up. As result, you not only obtain the number of classes in the package, but also in its subpackages, sub-subpackages, and so on. In Figure 35, the metric NumCls_tc yields the following values:

PackageNumCls_tc
package16
package1.13
package1.1.11
package1.21

Table 4: Example package metrics

As another example, the number of descendents of a class can be defined as follows:

<metric name="NumDesc" domain="class">
  <description>The number of descendents of a class.</description>
  <projection relation="genparent" target="generalization" 
              element="genchild" eltype="class" recurse="true"/> 
</metric>
Without the "recurse" attribute, this metric would count the number of children of a class. With "recurse" being set to true, the metric NumDesc is recursively evaluated for each child class, and added to the total.

Care must be taken when the "recurse" attribute is combined with the filter attributes (target, targetcondition, eltype, element, condition, scope). The filter attributes are NOT evaluated for the selection of elements on which to apply the metric recursively. The metric is always recursively applied to all elements in the unfiltered projection that are compatible with the element for which the metric is calculated. Consider this example:

<metric name="NumDesc_SameScope" domain="class">
  <projection relation="genparent" target="generalization" 
              element="genchild" eltype="class"
              scope="same" recurse="true"/> 
</metric>
This will not work. While only child classes in the same scope are counted, the metric is recursively applied to all child classes (regardless of their scope), and the number of their "same scope descendents" is added to the total. To define the intended metric, you would first define the set (see Section 8.5.3 "Set Expressions") of descendents of the class, and then define a projection to filter the classes with the desired scope in that set.