ApplicationDomains are pretty much a neverending source of confusion and suffering, but they provide an interesting palette of class definition partitioning.

Anyone building an application that dynamically loads SWF files needs to learn and love the AppDom rules…

The RulesAppDoms are containers for AS3 definitionsGenerally classes, but also functions and namespaces. You will use the “getDefinition” call to get a reference to one of these definitions, which you might then cast to a Class or a Function.AppDoms are hooked together into a tree, linked by “parentDomain” pointers. The topmost AppDom is the system domain, and it contains the built-in Flash types like Sprite, TextField, etc.If a definition already exists in a parent AppDom, the definition in the child is ignored.This always surprises people. As developers, we’re used to thinking of definitions as following the most local scope. Some reasons why we didn’t do it that way include:

  • The app doing the loading should be the master of the things it loads
  • Flex applications loading Flex applications would would double the memory use if the child used its own class definitions.
  • It reduces some security worries about classes being replaced.
  • It simplifies the implementation of manager singletons (the static parent version is used by the children)
  • Its closer to the old AS2 behavior, where classes were defined via some code that looked something like “if (!_global.Classname) {_global.Classname = …}”, which is a model that the Flex frameworks expects.
  • You can mimic the benefits of the “child wins” behavior by simply rooting a new AppDom on the System domain.

You may or may not find the above arguments compelling. Its still a source of controversy, even internally.AppDoms live within a single SecurityDomainCrossing a security boundary isn’t allowed.without explicit trust.UsageOk, good. So there’s the rules. How do you use them? Lets say that you’re dynamically loading a SWF:

var myLoader:Loader = new Loader();

You have some options. Perhaps..

myLoader.applicationDomain = new ApplicationDomain()

This creates a new domain, rooted on the System domain. What this means is that the classes in this domain are guaranteed to not collide It also means that you can’t talk to them in a strongly typed manner, all you can do is use “getDefinition”, and talk to them as Object (or other base Flash types).

myLoader.applicationDomain= new ApplicationDomain(ApplicationDomain.currentDomain)

This creates an ApplicationDomain as a child of the current application. This is the default for the Flex framework, as it allows strongly typed references to the child classes. For example, a dynamically loaded Flex application will be of type IFlexDisplayObject.

myLoader.applicationDomain = ApplicationDomain.currentDomain

This means that new classes will actually be added to the current application context. This is normally used for Runtime Shared Libraries (RSLs), and isn’t especially useful otherwise. The basic issue is that dangling (“externs”) references to classes must be fulfilled before the Actionscript Bytecode (ABC) block containing the references is ever initialized. This is usually carefully choreographed by ensuring that RSLs are dynamically loaded on the first frame of the application, before any of the classes that depend on the RSL are ever seen. Its hard to imagine any non-RSL case where adding classes to the current AppDom would be better than loading into a child AppDom.Here’s where stuff gets weird…ApplicationDomain.currentDomain is nutty. It isn’t what you think it should be. Heck, it isn’t what I thought it would be, and I helped design ApplicationDomain!The definition of ApplicationDomain.currentDomain is the ApplicationDomain that contains the code that is calling ApplicationDomain.currentDomain.This is all well and good, until you make a utility function to do something like:

function create(className:String):Object{var clazz:Class= Class(ApplicationDomain.currentDomain.getDefinition(className);return new clazz();}

and then you use that utility function both in a parent application and in a dynamically loaded child application. The child’s version is ignored (since its in the parent), and the meaning of “current” shifts to mean the parent! So, its basically impossible for the child to call a shared utility function to get a definition from its own domain unless you pass a handle to currentDomain in, which is often rather inconvenient.This weirdness has never failed to surprise us. In fact, we’re shipping with a deferred bug in the FlexModuleLoader class (used bySimpleApplication) that exhibits exactly this problem – it tries to find the application class, but fails if both the parent and child are derived from SimpleApplication. Oops. We’ll send the fix for this out in the first updater.The solution to this nightmare is to ensure that the code calling ApplicationDomain.currentDomain is unique to that particular SWF. The only class that you can generally assume to be unique is the root class of the SWF (for MXML-based Applications, its a compiler-generated subclass of SystemManager. For Actionscript-based code extending SimpleApplication, its a compiler-generated subclass of FlexApplicationBootstrap.) If you extend Sprite or MovieClip, its up to you, as the compiler doesn’t generate a unique subclass, you’re just getting a one-frame movie based on your class.In my next post, I’ll get back to discussing modular applications that take advantage of ApplicationDomain to partition classes cleanly for dynamic loading.

2 Responses to ApplicationDomain

  1. You say, “Its hard to imagine any non-RSL case where adding classes to the current AppDom would be better than loading into a child AppDom.”What about the case where the parent application contains no external references to the loaded classes; all the parent ever does is call getDefinitionByName() to pick up dynamically loaded definitions. In that case, it does seem simpler to just fold additional class defs from loaded SWFs into the parent AppDom, just as with RSLs. The choreography of loading doesn’t seem to apply here because there are no messy externs to deal with.

  2. Marcelo de Moraes Serpa says:

    Very nice article Roger.Despite all the complexity involved in this new architecture, I can see that all the dirty tricks we used to use on the previous AVM to allow shared-assets and classes are now solved.