Determining the relationship between Class and Interface objects in ActionScript

In ActionScript, the is operator can tell you whether a particular object is an instance of a given class or interface, but how can you tell the relationship between a Class itself and another Class or a Class and an interface?

That is, how can you check whether

var a:Class = Panel;
var b:Class = UIComponent;
var result:Boolean = (a is b); // ????

It turns out you have three options for doing this. The above does not work since a is a Class and Class is not a subtype of UIComponent.

1. Make an instance

public function classIsClass(a:Class, b:Class):Boolean {
   return (new a()) is b;
}

This is the most direct method but it has some limitations:

2. Use getQualifiedSuperclassName()

private function classIsClass(clsA:Class, clsB:Class):Boolean {
   if (clsA === clsB) return true;
 
   do {
      var superName:String = getQualifiedSuperclassName(clsA);
      clsA = getDefinitionByName(superName) as Class;
      if (clsA === clsB) {
         return true;
      }
   }
   while (clsA != Object);
 
   return false;
}

This method can’t handle interfaces at all. Since getQualifiedSuperclassName only walks the class inheritance chain, it will never touch the interfaces of clsA. If clsB is an interface, this method will always return false. If clsA is an interface, this method will throw an error since getQualifiedSuperclassName returns null for interfaces.

3. Use describeType()

public function classIsClass(a:Class, b:Class):Boolean {
   if (a === b) return true;

   var aXML:XML = describeType(a);
   var bXML:XML = describeType(b);

   return aXML.factory.extendsClass.(@type == bXML.@name[0]).length() == 1 ||
        aXML.factory.implementsInterface.(@type == bXML.@name[0]).length() == 1;
}

This method eliminates the problems of the first 2 method, but at the cost of performance. describeType is an expensive method. It returns an XML document describing every aspect of a given object. If you are only running this check a few times, this cost is negligible, but for many calls it can add up quickly. describeType is also stupid; 2 successive requests to describe the same object will cause all the XML to be generated twice. If you know that you will be checking the same types many times, I strongly urge you to consider caching the description XML.

Performance Comparison

I set up a test with 25 random classes from the Flex API and used each method to compare every class to every other class (including themselves). I used the Flash Builder profiler to record time in each method.

Method # of test runs Cumulative time Average cumulative time
Create an instance 1625 381 ms 0.23 ms
Use getQualifiedSuperclassName 1625 181 ms 0.11 ms
Use describeType 325 11391 ms (11027 ms of this spent running describeType) 35.05 ms
Use describeType with XML cached after first request 325 717 ms 2.2 ms

Comments