describeType vs. describeTypeJSON
flash.utils.describeType has been around since Flash 9 and is the standard way to find out interesting information about a Class type, including its metadata/annotations. However, there’s a hidden function called describeTypeJSON that provides an interesting alternative. Since describeType is notoriously slow, could describeTypeJSON be the speedy alternative we’ve been looking for? Today’s article puts them to the test!
First of all, you should read the excellent article by Till Schneidereit about describeTypeJSON to find out lots about its internals. Suffice to say that it’s a hidden function in the avmplus package with no public visibility. We therefore need to create a wrapper class in the avmplus package so we can get at it. Thankfully, the SwiftSuspeners project has provided just such a class.
So what do you get out of describeTypeJSON? Well, just like when you use the JSON class to parse a String, you’ll get an untyped Object. As an example, I tested this simple class:
package { public class Person { public var name:String; public var age:int; public var alive:Boolean; } }
And printed the Object that describeTypeJSON returned with a simple recursive function:
function printObject(obj:Object, numTabs:int=0): void { var tabs:String = ""; for (var i:int = 0; i < numTabs; ++i) { tabs += "\t"; } for (var k:* in obj) { var v:* = obj[k]; trace(tabs + k + " = " + v); if (v) { printObject(v, numTabs+1); } } }
Here’s what I got:
isDynamic = false isStatic = false name = Person traits = [object Object] interfaces = methods = null accessors = null bases = Object 0 = Object metadata = [object Object] 0 = [object Object] value = [object Object] 0 = [object Object] value = 24 key = pos name = __go_to_definition_help constructor = null variables = [object Object],[object Object],[object Object] 0 = [object Object] uri = null name = alive access = readwrite metadata = [object Object] 0 = [object Object] value = [object Object] 0 = [object Object] value = 95 key = pos name = __go_to_definition_help type = Boolean 1 = [object Object] uri = null name = name access = readwrite metadata = [object Object] 0 = [object Object] value = [object Object] 0 = [object Object] value = 47 key = pos name = __go_to_definition_help type = String 2 = [object Object] uri = null name = age access = readwrite metadata = [object Object] 0 = [object Object] value = [object Object] 0 = [object Object] value = 73 key = pos name = __go_to_definition_help type = int isFinal = false
The formatting isn’t great, but you can clearly see that the output is very similar to what we get from good old describeType:
<type name="Person" base="Class" isDynamic="true" isFinal="true" isStatic="true"> <extendsClass type="Class"/> <extendsClass type="Object"/> <accessor name="prototype" access="readonly" type="*" declaredBy="Class"/> <factory type="Person"> <extendsClass type="Object"/> <variable name="alive" type="Boolean"> <metadata name="__go_to_definition_help"> <arg key="pos" value="95"/> </metadata> </variable> <variable name="name" type="String"> <metadata name="__go_to_definition_help"> <arg key="pos" value="47"/> </metadata> </variable> <variable name="age" type="int"> <metadata name="__go_to_definition_help"> <arg key="pos" value="73"/> </metadata> </variable> <metadata name="__go_to_definition_help"> <arg key="pos" value="24"/> </metadata> </factory> </type>
Now on to the main point of this article: speed. Which is faster? Let’s run each 10,000 times and see. Here’s a little test app that does just that:
package { import flash.display.*; import flash.utils.*; import flash.text.*; import avmplus.*; public class DescribeTypeSpeed extends Sprite { private var logger:TextField = new TextField(); private function row(...cols): void { logger.appendText(cols.join(",") + "\n"); } public function DescribeTypeSpeed() { stage.align = StageAlign.TOP_LEFT; stage.scaleMode = StageScaleMode.NO_SCALE; logger.autoSize = TextFieldAutoSize.LEFT; addChild(logger); init(); } private function init(): void { const REPS:int = 10000; var i:int; var beforeTime:int; var afterTime:int; var describer:DescribeTypeJSON = new DescribeTypeJSON(); row("Operation", "Time"); beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { flash.utils.describeType(Person); } afterTime = getTimer(); row("describeType", (afterTime-beforeTime)); beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { describer.getInstanceDescription(Person); } afterTime = getTimer(); row("describeTypeJSON", (afterTime-beforeTime)); } } }
I tested this app using the following environment:
- Release version of Flash Player 14.0.0.125
- 2.3 Ghz Intel Core i7-3615QM
- Mac OS X 10.9.2
- Google Chrome 35.0.1916.153
- ASC 2.0.0 build 354130 (
-debug=false -verbose-stacktraces=false -inline -optimize=true)
And got these results:
| Operation | Time |
|---|---|
| describeType | 643 |
| describeTypeJSON | 135 |

It turns out that describeTypeJSON is about 5x faster than describeType. This means it’s probably worth jumping through the hoops necessary to get access to the hidden functionality. The access is still pretty slow (0.135 ms each on this relatively-fast machine), so don’t call the function more than you need to.
One tried-and-true method of optimizing this is to cache the results in a static Dictionary since the types don’t change at runtime. This makes subsequent calls to either describeType or describeTypeJSON almost free. If you do this, the speedup gained from describeTypeJSON will only apply to the first call to describe a Class, but even that can be quite significant.
Spot a bug? Have a question or suggestion? Post a comment!
#1 by ben w on June 23rd, 2014
Thought it would be faster, but I would also mention the fact that you can filter the output with flags.
If you were after variable metadata only your might not need all of them…
i.e. you could maybe ignore
avmplus.INCLUDE_CONSTRUCTOR
avmplus.INCLUDE_METHODS
avmplus.INCLUDE_ACCESSORS
if you knew you were only after:
avmplus.INCLUDE_VARIABLES
It could lead to a bigger speed increase as less information is needed, with the traditional describeType all the info is returned regardless how much of it you are interested in.
#2 by jackson on June 23rd, 2014
Very good point! I tried just
avmplus.INCLUDE_VARIABLESand got about 12-13 ms on the same machine, a 10x speedup. It compares apples to oranges, but sometimes you’re not after everything indescribeType’s package deal.#3 by Deril on June 24th, 2014
Hi,
I did research on it half year ago.. if you drop metadata stuff you get about *10 increase over describeType.
https://github.com/MindScriptAct/mvcExpress-framework/issues/19
#4 by jackson on June 24th, 2014
Glad to hear your results line up with my findings.
#5 by Alexander on June 26th, 2014
So 135ms / 10000calls will be equal to 0.134ms/1call? ))
#6 by jackson on June 26th, 2014
Yes, in the test environment. But the test CPU is really fast compared to slower chips such as those found in mobile devices. Here’s a random comparison I found of a CPU very much like the one in the test environment to the CPU in the iPad 1 and iPhone 4. The test environment CPU is about 28x faster, which translates to
describeTypeJSONtaking 3.752 ms/call. If you’re trying to get a game to run at 30 FPS, you only get 33.3 ms/frame, so 3.752 ms for adescribeTypeJSONcall takes up over 11% of your total CPU allotment. This means it’s really expensive.Now compare to looking up the cached results of
describeTypeJSONin aDictionary. In this article where I used the same CPU I could perform two millionDictionarylookups in 568 ms for an average of 0.000284 ms/call. Apply the 28x multiplier for iPad 1 or iPhone 4 and you get 0.007952 ms/call on those devices. That’s only 0.024% of your total frame time for 30 FPS, which is quite tolerable.#7 by Alexander on July 1st, 2014
I meant 135ms / 10k = 0.0135ms/call :-)