In AS3, if a class is marked as dynamic, new properties can be added and removed at runtime, by simply setting the property or removing it with the delete
keyword.
I am asking whether there is a faster way to determine whether a class is dynamic than calling the describeType
function and checking the "isDynamic" attribute value on the returned top-level XML node, for example: <type name="flash.display::MovieClip" base="Class" isDynamic="true" isFinal="true" isStatic="true">
.
I suspect there is a faster method, but all I really need to do is try to assign a property value if it exists or can be created.
//The "base is dynamic" test is pseudo-code since it's not valid
if (base.hasOwnProperty(propertyName) || (base is dynamic))
base[propertyName] = value;
else
throw new Error( "Property " + propertyName + " does not exist and cannot be created." );
Perhaps I would be better off just wrapping the assignment in a try/catch block and assuming the class is not dynamic when the assignment fails. If it succeeds, I don't care whether it's dynamic, since the goal is to simply assign the property value if exists or can be added.
try{base[propertyName] = value}catch(err:Error){/*property did not exist and class is not dynamic, or some other error occurred in the property setter*/}
My only issue with the try/catch approach is that I wouldn't know if the assignment failed because the property couldn't be assigned or if some other error occurred in the property setter. Even catching the error and checking its type will not tell me whether the error occurred at this precise point (as opposed to some other setter deep within this setters calling chain), because the getStackTrace method is only available in the debug player. That's why I really need to check whether the class is dynamic up front, so the assignment failure can be reliably predicted and avoided altogether. I will opt for a correct implementation over a faster one.
Since the only correct way to determine whether the property can be assigned is to check whether the property exists and whether the property can be created, I decided to focus on optimizing the determination of whether the instance is dynamic.
Although the describeType function may be relatively slow, I really only need to call it once per type if I cache the results. I could then store the boolean result in a dictionary by type name or class reference, and then just use the much faster functions getQualifiedClassName and/or getDefinitionByName methods to look up whether the class was dynamic.
public class ClassUtils
{
static var typeDescriptions:Dictionary;
static var isTypeDynamic:Dictionary;
public function isDynamic( instanceOrClass:* ):Boolean
{
var qname:String = getQualifiedClassName(instanceOrClass);
var isDynamic:* = isTypeDynamic[qname];
if (isDynamic === undefined) //only explicitly untyped variables can hold the value undefined with strict equality
{
var desc:XML = getCachedTypeDescription( qname );
isDynamic = Boolean(desc.@isDynamic);
isTypeDynamic[qname] = isDynamic;
}
return isDynamic;
}
public function getCachedTypeDescription( qname:String ):XML
{
var desc:* = typeDescriptions[qname];
if (desc === undefined) //only explicitly untyped variables can hold the value undefined with strict equality
{
desc = describeType( type );
typeDescriptions[qname] = desc;
}
return desc;
}
}
That in turn will allow my original implementation to function quickly and efficiently:
if (base.hasOwnProperty(propertyName) || (ClassUtils.isDynamic(base))
base[propertyName] = value;
else
throw new Error( "Property " + propertyName + " does not exist and cannot be created." );