I've been converting some of my old AS 1.0 utility classes over to AS 2.0 and I've run across a few quirks.
The first has to do with the venerable for...in construct. This should let you loop through a set of objects in an array, or a set of properties in an object. However the AS 2.0 compiler throws errors in some cases when iterating through properties, though the 1.0 compiler did not. It all seems to come down to dynamic classes, and understanding what it means to put "dynamic" in front of a class definition.
This one really threw me for a while. I have an XML serialization routine that takes an AS object, enumerates all of its properties, and formats it as generic XML. Very useful in a lot of situations. The core operation is this loop that gets an index for each property:
class com.appcentral.util.XMLUtil { function toXML(obj:Object):String { // code clipped here for brevity // get all properties of the object for (propIndex in obj) { // get the type and name of the property var propType_str = typeof obj[propIndex]; var propName_str = propname.toString(); // code clipped again
After converting my class to AS 2.0, I got the following compile-time error:
**Error** ..\com\appcentral\util\XMLUtil.as: Line 82: There is no property with the name 'propIndex'.
for (propIndex in obj) {
Perhaps the compiler didn't believe a generic Object could have properties?
I looked into the new concept of "dynamic" classes in AS 2.0 for a clue. Unless you explicitly define a class as "dynamic" you are not able to add properties (including functions) to that class at runtime. Greg Skinner provided a nice overview of this in his blog a few months back.
Macromedia had the foresight to make many of the core AS classes, such as MovieClip and LoadVars, dynamic from the start, so that developers could add new properties and functions on the fly.
Some other core classes that you'd expect to be dynamic are not, though. For example the Form class and the LocalConnection class are not dynamic, meaning you have to subclass these if you ever want to add poperties or new functionality. As a long-time OO advocate I have to say that subclassing's not at all a bad thing. But it sure was convenient to just add a new property to a core class and have it accessible by all instances without having to chenge the class references everywhere!
In comments on Mike Chambers' blog, folks suggested editing the Macromedia class definitions themselves to make certain classes like localConnection dynamic. That's one solution, but I'm always wary of changing Macromedia-supplied files lest one day they get overwritten by an upgrade, or your application gets ported to some platform that doesn't have the edited classes.
So the error message seemed almost insurmountable. It seemed to say that since Object class was not dynamic, you couldn't reference properties on the class. I didn't want to edit Object.as to make it dynamic--if Macromedia didn't do it that way, it probably wasn't meant to be.
I tried a few other ways to enumerate the properties of that incoming Object, to no avail. Finally in a frenzy of trial-and-error coding, I decided to make the XMLUtil class itself dynamic. Guess what, it worked. I didn't expect it to, because I thought the problem was with the Object class, not the XMLUtil class. This has caused me to reassess what dynamic actually does.
At first I assumed that setting a class dynamic meant what the Macromedia documentation says: "Objects based on the specified class can add and access dynamic properties at runtime." All the examples in the docs deal with adding new properties to the instance of the specified class, not to other associated classes. But it seems this also applies to objects passed in as parameters to functions on the specified class! Maybe the true effect is described by the next line in the docs:
"Type checking on dynamic classes is less strict than type-checking on nondynamic classes..."
In other words, "dynamic" doesn't just relax the type-checking for the class' own members. It tells the compiler to stop being so strict about all type-checking of dynamic properties in the class, even for function parameters and the like.
The moral of the story: if you start seeing a lot of "There is no property with the name..." error messages, try making your class dynamic.
do var propIndex instead of propIndex; that's one compiler tricker.
Second, you could do:
this["propIndex"]
That's another way.
Third, if your just making your class dynamic because you can't do:
my_xml = new XML();
my_xml.owner = this;
Then do:
my_xml["owner"] = this;
Finally, shorthand:
var owner = this["owner"];
Saves in typing. LONG LIVE COMPOSITION!
Posted by: JesterXL | 30 December 2003 at 02:35 PM
Jester, Thanks for the great tips! Yes doing
for (var propIndex in obj)
takes care of the compiler errors. Without the var it must be type-checking the name "propIndex" against the stated properties of the object and not finding it there.
I still find it strange that putting "dynamic" in front of the class definitions prevents this kind of type-checking!
Posted by: Rob Dixon | 30 December 2003 at 03:27 PM
Great article!
I've been porting all of my JavaScript collection of String (14 additoinal handy methods for the string alone) and Number helper methods to ActionScript the past few days. I ran into the same problem. When I did something as simple as this:
String.prototype.MyMethod = function ( Void ):String { return this; };
I was getting that error you mentioned above. I finally resolved to add my function declarations to the String.as file that came with Flash.
The drawback, as you mentioned, is that if I load that FLA onto a computer at the office that does not have the modified core AS file, the FLA will compile with errors. But, I feel it's a tiny, albeit a clumsy way to get my neato and handy little methods into the core objects.
Posted by: Andy | 05 October 2006 at 04:30 PM