In doing Flash Development for a multi-swf site, we ran into the “first class wins” problem. Basically, an ActionScript class’ bytecode is stored with the SWF that uses it. If the compiler detects a SWF being used, it’ll compile it in. This means, in a website that utilizes multiple SWF’s, 2 SWF’s that utilize the same class will both have their own copy. This is a waste of filesize which costs the user bandwidth.
All classes in Flash Player 8 and below are stored on the _global namespace. This is a special object added in Flash Player 6 that allows the storage of data common to all SWF’s that are loaded in dynamically at runtime, either via loadMovie or loadMovieNum. Before _global, classes were stored on _level0 …usually.
Flash Player 8 and below have a concept of levels. These allow SWF’s to be stacked on top of one another. You could do the same thing with MovieClips stacked on top of one another, but they had to exist in _root. Levels on the other hand each had their own _root. Now, there was a safe way to ensure every SWF was looking at the same data, and a great place to put classes.
No class could be overwritten, however. Classes are basically written in an #ifdef fashion behind the scenes when using ActionScript 2, like so:
// if the class isn't defined" if ( _global.Ball == undefined) { // define it _global.Ball = function(){}; }
Using that code above as a base, you can see how all subsequent loading of SWF’s have their classes of the same name / package ignored. The Flash Player assumes it’s already loaded, and thus does not use the class bytecode in the loaded SWF. On a job I’m on currently, we ran into this problem. We put a trace in our code, and it never ran when we deployed our SWF to the website. That’s because the website was already loading a SWF that had the same class, and thus was ignoring our new one since our SWF loaded later. Again, first class in wins.
This same problem also exhibited itself with loading applications into Central, Macromedia’s early foray in getting SWF applications onto the desktop (pre Apollo). Since Central was a SWF loader of sorts, you’d have classes left defined on _global, like they should be. This caused problems however, when you would load in a new SWF to test and not see your changes. If you didn’t reload Central, or delete your class from _global, it’d stick around, and your newly loaded SWFs would use the old classes.
The way class definitions work with loaded SWFs is not a bug and is by design for a few reasons. Additionally, it has been significantly improved in Flash Player 9.
Paraphrasing Roger’s entry about flash.system.ApplicationDomain, the justifications are basically:
- A Loader should control what it’s loading
- Classes not being replaced by loaded SWFs eases security concerns
- Makes static / Singleton implementations predictable, and work with child content accessing the same classes
There are others, but those are the ones relevant to this discussion concerning Flash Player 8 and below.
You can additionally use this implementation to your advantage. Roger discusses some ways with the pro’s can con’s to each with regards to Flex development. For Flash development, some additional points are a little different.
For example, using Interfaces to allow 2 or more SWFs to talk to each other prevents the same class being included in both SWFs, and thus saving space. This includes all class dependencies, so you can see how this is a great way to encourage the good practice of coding by contracts (using interfaces) with strong-typing, both in ActionScript 2 and 3. This also prevents you from having to go through the laborious process of using Remote Shared Libraries. While RSL’s are great, there are currently no good tools (aside from ANT in Eclipse which Flash doesn’t have) to help management of RSL’s, thus they are a card house. When you get them working, they rock and look great. They are not change friendly; one breeze of scope creep or refactoring, and the whole thing comes crashing down. Hell, if it makes Darron Schall sweat, you know they are hard.
Roger mentions that using implied dependencies via external-library-path isn’t such a good idea because the reverse, having the shell exclude loaded classes, doesn’t work as a use case and is backwards. With context to Flash, I disagree with the first part. I do agree that a shell excluding child classes is silly. Now, interfaces imply you have a good API designed. Our API and designs fluctuate daily. While I agree with Roger that usually your implementation changes, yes, in application development, I’d agree. However, in the Flash world, the shiz is chaos. It may sound like a cop-out, and it is. I refuse to write good code knowing it’ll get torched tomorrow. I’d rather write working code that is maintainable and flexible enough to adjust to change requests. If 20% of what I’ve been writing dies, so be it. In the design world, things change down to the deadline. We also don’t have the kind of time to “flesh out” out our API’s. We can make a great first pass, yes, but when your design can change at a moment’s notice, what’s the point? “Man, this ComboBox is phat! It extends our base TweenComponent, and moves really well in that list. Huh? What do you mean they want the list items to fade in now vs. the list zooming up!? I thought they liked it and signed off on it last week? Son of a LKEJRLKJgfdsjglkdfjg””. That’s not sarcasm; it does happen, a lot. Imagine re-writing an entire list component and all sub-classes… it sucks. Will you now spend the same amount of time hammering out an API… or just make it “good enough”? What if you suddenly have no need for a List in the first place?
Using the exclude.xml functionality built into Flash, having loaded SWF’s exclude classes that the shell will contain for them can work quite well. The trade off is, you need to remember to compile the “framework.swf” every time you make a change to a shared class. That way, all of your child SWF’s that are loaded into the main one use the same class, and are smaller since they don’t have to keep a copy of it.
How do you create & mange this framework FLA without tools like ANT? JSFL – JavaScript for Flash. There are four things you need to do.
First, you need to identify commonly used classes. These are classes, visual components and/or utility classes, that many FLA’s use. You then put these, like so, into a framework.fla on frame 1:
com.company.project.Class;
Notice the lack of import. Flash will recognize that as a usage and compile the class into the SWF. Keep in mind you do not need the MovieClip assets that go with visual components. With Flash Player 8 and below, these cannot be shared in a simplified fashion. Thus, you’re best bet is to externalize your bigger assets like images and sounds so they’ll be downloaded to the internet cache, and other SWF’s can load the same images and sounds. For frameworks like the mx one, it’s kind of a big deal, because the base component framework has a lot of built-in graphic assets that now have to be duplicated in many SWF’s. However, most design frameworks are made to be skinned, and thus are usually just lightweight MovieClips; containing a bounding box, a stop, and maybe more lightweight base classes on their assets layer, so this really isn’t that bad.
The second thing to do is to write a JSFL script that can auto-generate exclude.xml files. These text files that must reside next to your FLA file must also have the name yourfile_exclude.xml where the yourfile is replaced with the name of your FLA file. When you compile your FLA, Flash will look for this file, and if it finds it, it’ll make sure NOT to include any classes listed in the exclude.xml file in the SWF.
What your JSFL file will do is loop through all library items, and if it finds a class that is used the base framework, it’ll make sure to add that class to the list in the exclude.xml.
The downside? You won’t be able to test this SWF locally. That is unacceptable. Therefore, the third thing you need to do is to write another JSFL that deletes the exclude.xml file if there, and then performs a test movie.
Both of the above JSFL files can run in Flash MX 2004 7.2 and Flash 8 which both include the FLfile.dll. This allows JSFL to read and write text fields.
With Flash Player 9, it’s different. It also depends on if you are using the Flex 2 framework or not. Without repeating Roger’s good entry on it, Flash Player 9 has made a new place to manage the different sections where these classes are. The reason for this is because SWFs are no longer always tied to the display. Now, with the DisplayList, classes that represent display objects can exist independently, and need to be managed someplace with relation to, but not being tied to, the DisplayList. There is also a little more control over how these loaded classes are handled, and where they are stored.
When loading a SWF, you can determine which AppDom (pronounced like Kingdom – Roger’s slang for them) the Loader will use when loading the SWF. When the SWF is loaded, the classes are held in that context.
Someone, sometime, is going to have to handle this for ActionScript 3 in an easier way than is done currently with regards to Flash. Not all of us are building Enterprise Applications with SWF. Some of us don’t need the large Flex 2 component framework for our work. We need something lighter weight, like the set that Grant n’ Friends are working on for Flash 9 (Blaze), with less dependencies so it’s easier to modularize classes without the need for interfaces and Remote Shared Libraries.
Again, I agree with Interfaces with regards to Flex 2 apps, but in the design world, we don’t have that kind of time, nor can we garner that kind of commitment to API’s. Until I get a better IDE, I’ll never agree with RSL’s. To be fair, I haven’t given them a hardcore run through in a sizable Flex 2 project yet.
Anyway, I haven’t had time to peruse Roger’s Module source yet, but the “on the fly class loader” sounds pretty hot. It’d certainly make that skins on the fly tons easier via DLL-like SWFs, yes? I hope to write more about this subject in the future when I have some scripts to show as well as example file size savings. Additionally, while some bitch about how it’ll be hard to do this kind of stuff with the Flex 2 framework, SOME of it can be done, enough to make a positive impact I’m sure. When I’m done doing Flash consulting, hopefully I can jump back to some Flex 2! Till then, attach this.