I recently received a tip about a thread discussing an interesting problem: how to tell if one Class object represents a class that subclasses another Class object. If you had an instance of the class, you could simply use the is or instanceof keywords, but that won’t do here. Today’s article shows how to solve this tricky problem.

The aforementioned thread points to a couple of workable solutions. The first uses a combination of getDefinitionByName and getQualifiedSuperclassName in a loop to iterate until the superclass is found. Here is the version posted by player_03: (formatting applied by me)

private function isSubclassOfP03(type:Class, superClass:Class): Boolean
{
	if (superClass == Object)
	{
		return true;
	}
	try
	{
		for (
			var c:Class = type;
			c != Object;
			c = Class(getDefinitionByName(getQualifiedSuperclassName(c)))
		)
		{
			if (c == superClass)
			{
				return true;
			}
		}
	}
	catch(e:Error)
	{
	}
 
	return false;
}

Iterating on these expensive function calls seems slow and the function itself is quite large, so skyboy offers an alternative that takes advantage of the prototype field and the instanceof operator. The prototype field is present on all valid objects and essentially tells you what made the object, which is usually its Class. The instanceof operator is deprecated (you’ll get a warning), but can be used for just the purposes we’re looking for: Class instanceof Class. With some (optimized) error checking and a good catch for when the two Class objects are the same, here is his version: (with minor editing by me)

private function isSubclassOfSkyboy(a:Class, b:Class): Boolean
{
	if (int(!a) | int(!b)) return false;
	return (a == b || a.prototype instanceof b);
}

Much smaller and it has no loops! So, let’s test them out to make sure they both work:

package
{
	import flash.display.*;
	import flash.text.*;
 
	public class MyApp extends Sprite
	{
		private var __logger:TextField = new TextField();
		private function log(msg:*): void { __logger.appendText(msg + "\n"); }
 
		public function MyApp()
		{
			var logger:TextField = __logger;
			logger.autoSize = TextFieldAutoSize.LEFT;
			addChild(logger);
			log(isSubclassOfP03(int, int));
			log(isSubclassOfP03(MyApp, MyApp));
			log(isSubclassOfP03(MyApp, Sprite));
 
			log(isSubclassOfSkyboy(int, int));
			log(isSubclassOfSkyboy(MyApp, MyApp));
			log(isSubclassOfSkyboy(MyApp, Sprite));
		}
 
		private function isSubclassOfSkyboy(a:Class, b:Class): Boolean
		{
			if (int(!a) | int(!b)) return false;
			return (a == b || a.prototype instanceof b);
		}
 
		private function isSubclassOfP03(type:Class, superClass:Class): Boolean
		{
			if (superClass == Object)
			{
				return true;
			}
			try
			{
				for (
					var c:Class = type;
					c != Object;
					c = Class(getDefinitionByName(getQualifiedSuperclassName(c)))
				)
				{
					if (c == superClass)
					{
						return true;
					}
				}
			}
			catch(e:Error)
			{
			}
 
			return false;
		}
	}
}

Here are the results showing that they all pass:

true
true
true
true
true
true

Now let’s look at a little app to test for performance:

package
{
	import flash.display.*;
	import flash.utils.*;
	import flash.text.*;
 
	public class ClassInheritance extends Sprite
	{
		private var __logger:TextField = new TextField();
		private function row(...cols): void
		{
			__logger.appendText(cols.join(",")+"\n");
		}
 
		public function ClassInheritance()
		{
			var logger:TextField = __logger;
			logger.autoSize = TextFieldAutoSize.LEFT;
			addChild(logger);
 
			row("Version", "Time");
 
			var beforeTime:int;
			var afterTime:int;
			var REPS:int = 1000000;
			var i:int;
 
			beforeTime = getTimer();
			for (i = 0; i < REPS; ++i)
			{
				isSubclassOfSkyboy(MyApp, Sprite);
			}
			afterTime = getTimer();
			row("Skyboy", (afterTime-beforeTime));
 
			beforeTime = getTimer();
			for (i = 0; i < REPS; ++i)
			{
				isSubclassOfP03(MyApp, Sprite);
			}
			afterTime = getTimer();
			row("player_03", (afterTime-beforeTime));
		}
 
		private function isSubclassOfSkyboy(a:Class, b:Class): Boolean
		{
			if (int(!a) | int(!b)) return false;
			return (a == b || a.prototype instanceof b);
		}
 
		private function isSubclassOfP03(type:Class, superClass:Class): Boolean
		{
			if (superClass == Object)
			{
				return true;
			}
			try
			{
				for (
					var c:Class = type;
					c != Object;
					c = Class(getDefinitionByName(getQualifiedSuperclassName(c)))
				)
				{
					if (c == superClass)
					{
						return true;
					}
				}
			}
			catch(e:Error)
			{
			}
 
			return false;
		}
	}
}

I ran this performance test with the following environment:

  • Flex SDK (MXMLC) 4.5.1.21328, compiling in release mode (no debugging or verbose stack traces)
  • Release version of Flash Player 10.3.183.10
  • 2.4 Ghz Intel Core i5
  • Mac OS X 10.7.1

And got these results:

Version Time
Skyboy 64
player_03 1137

Checking Class Inheritance Performance Chart

The performance of the skyboy version blows away the competition by a factor of about 20x, making it the clear winner. So, next time you need to check if a Class extends another class, keep this function in mind.

Spot a bug? Have a suggestion? Post a comment!