Weak References

In one of my introductions to this series about cross-compiling ActionScript to JavaScript I suggested dividing all features necessary for cross-compiling ActionScript from pre-existing Flex and Flash projects to JavaScript into two buckets, language features and runtime features. With language features I meant features like classes and inheritance while runtime features referred to Flash Runtime and browser features like Sprite and Element.

I hope that I have covered the most important language feature topics in these last posts:

  1. 0.2 + 0.1 = 0.30000000000000004
  2. Classes, Inheritance, Interfaces, Packages, and Namespaces
  3. Const, Types, For/Each, and E4X
  4. Getting “this” right
  5. Static Initializers
  6. Do Arrays and Objects have side effects?

At this point we should be ready to move on and shift our focus towards the runtime features bucket. As we are doing so we first stumble over a group of odd features that seem to be right in the middle between language features and runtime features. Those are Weak References, Proxy, and Dictionary.

 

The Weak and the Strong

Before ActionScript 3 only Strong References existed: When your code used an Object the virtual machine also increased a reference counter associated with that Object. When an Object was not needed anymore the virtual machine would detect that and decrease the reference counter. Periodically the virtual machine’s Garbage Collector would destroy all objects whose reference counter was 0, which indicated that an Object was not any longer in use. With Weak References you can now also reference Objects without increasing their reference counter, which would allow the Garbage Collector to release more memory. There is a flip side to this feature, because weakly referenced Objects might get disposed by the Garbage Collector and your members and variables may become null at any time. You can never assume that a weakly referenced Object is still alive (unless you hold a separate strong reference to that Object of course, which would defeat the purpose).

There are only two places in the Flash Runtime API where weak references are currently supported. One is EventDispatcher.addEventListener and the other one is Dictionary.

flash.events.EventDispatcher:
public function addEventListener(type:String,
listener:Function, useCapture:Boolean = false,
priority:int = 0, useWeakReference:Boolean = false):void

If you no longer need an event listener, remove it by calling removeEventListener(), or memory problems could result. Event listeners are not automatically removed from memory because the garbage collector does not remove the listener as long as the dispatching object exists (unless the useWeakReference parameter is set to true).

flash.utils.Dictionary:
public function Dictionary(weakKeys:Boolean = false)

Instructs the Dictionary object to use “weak” references on object keys. If the only reference to an object is in the specified Dictionary object, the key is eligible for garbage collection and is removed from the table when the object is collected. Note that the Dictionary never removes weak String keys from the table. Specifically in the case of String keys, the weak reference will never get removed from the key table, and the Dictionary will keep holding a strong reference to the respective values.

If you are interested in more details about Weak References I recommend Grant Skinner’s article about AS3: Weakly Referenced Listeners and Weak vs Strong References in AS3 by Mims H. Wright.

What shall we do with those two APIs when cross-compiling to JavaScript, which does not support weak references? The short answer is: We cannot emulate weak references in JavaScript, because the browser’s Garbage Collector does not support this feature. The good news is that weak references is the only ActionScript feature that cannot be emulated in JavaScript.

Here is what we could do:

  1. The runtime code could throw an error when useWeakReference or weakKeys  are set to true.
  2. The runtime code could set that all weakly referenced Objects always to null as if they had been immediately disposed.
  3. The runtime code treats weak references always as strong references.

All three proposals have their pros and cons. In my opinion #2 is the worst solution, because it would break a lot of pre-existing ActionScript code. Technically, client code must not assume that weakly referenced Objects are always available. But in reality nobody expects the Garbage Collector to be that quick. Solution #1 is perhaps the cleanest solution but is also an annoying one, because it forces changes in the client code. The last solution is just cheating and may cause serious memory problems at runtime.

How about this solution?

4. Combine #1 and #3 using Dart Rules: Throw an error at runtime when useWeakReference or weakKeys  are set to true in debug (“checked”) mode. Don’t throw an error in release (“production”) mode but instead treat weak references always as strong references.

That might be the way to go.