Archives

I think one of the handiest new features in ActionScript 3 is the Dictionary object, which lives in the flash.utils package. It is a new object type that allows you to associate a value with an object key. This is similar to how array associates values with numeric indexes, and how you can use a generic object to associate a value with a string key.

You can use any type of object as a key, not just generic objects (you could use a Sprite, or an Array, for example). This includes primitives (string, boolean, number, int, uint) which are matched based on value (again, strict equality):

for(varkey:Objectin dict){// iterates through each object key}foreach(var value:Objectin dict){// iterates through each value}

You can also set a Dictionary to use weak references as keys. This is pretty cool, because it means that if you clear all references to an object except those in a weakly referenced dictionary, that object will be available for garbage collection, which in turn will release the reference to its value.

In the above example, the Sprite is now available for collection, which in turn will free the Object for collection. This can be a very handy tool for creating memory management tools, and anywhere that you want to keep lists of objects but not interfere with their collection.

Dictionary objects can be really handy for maintaining object lists / queues, such as a doLater queue for functions (though please note the bug mentioned below), a listeners list for a custom event system, a list of Sprites in a game, or a list of row-renderers in a list component. You could cross-reference an array and a dictionary for quick look-ups in ordered lists (ex. a depth manager) – the array would hold references to objects in the appropriate order, and the dictionary would hold array indexes keyed to the objects themselves.

It can also be used for associating meta data with sealed objects. For instance, a layout manager might need to store extra data about the components it is managing, so instead of injecting that data into the component arbitrarily (which won’t work in AS3 anyway), it can maintain a Dictionary that uses weak references to the components as keys, and stores the extra data as the values. This opens the door to a lot of interesting new options from a code architecture perspective.

Note that there is a known bug with Dictionary that prevents it from operating correctly with references to methods. It seems that Dictionary does not resolve the method reference properly, and uses the closure object (ie. the “behind the scenes” object that facilitates method closure by maintaining a reference back to the method and its scope) instead of the function as the key. This causes two problems: the reference is immediately available for collection in a weak Dictionary (because while the method is still referenced, the closure object is not), and it can create duplicate entries if you add the same method twice. This can cause some big problems for things like doLater queues.

I’ll be discussing more about how you can use Dictionary objects with weak references in my next article on resource management.

Post navigation

34 Comments

this sounds very interesting, but I have 1 question: if I have used an object as the key, then later on the object gets garbage collected, if I “for each” through the dictionary has the weak reference just vanished or will there be some residual trace of it (like a null key or something)?

“like how something was done in AS2 and how Dictionary class can help in replacing that to make life simpler.”

Say you need to check a couple of objects for something (nodes in a pathfinding routine for intsance), and you want to keep track of which objects have been checked this frame. You could set a checked-parameter to true on all of them, which means you’ll have to set it to false for the next time you go through the objects.

Or you could store them in an array – ie checkedObjects.push(someObject) but to see if an object has been checked, you’d need to loop through everything to see if the current one has been checked – unless you give them all a unique index or something.

Enter the dictionary. Just do checkedObjects[someObject]=true and to see if it has been checked you can do if(checkedObjects[someObject]) { etc }. Just delete the reference to the checkedObjects dictionary after you’re done.

That’s just one example that comes to mind. I’m using it for my tile engine too, and there’s tons of possible applications for it.

A few days ago, I did some benchmarking, and came to the conclusion that a dictionary is in fact faster than an array, but it was a quick-and-dirty test so I wouldn’t call it conclusive at all. I’d like it if Mr Skinner, or anyone else could verify this.

Ow, and another thing that’s cool about dictionaries is that you can easily delete an object from it.

If you’d use an array, you would have to loop through it to find the index of the object, and splice the array there. In a dictionary, since the objects are the keys, you can just delete myDictionary[someObject], which is easier, and probably faster (haven’t checked, but it should be, especially when there’s lots of data in it).

This is very cool I use a function like mentioned above that I dance through arrays regurlarly to look up an object base on instance name of the movie clip. This would be great for going directly to the OBject instance based on the object itself. And not have to loop through an array and match it based on name. I do like doing look up’s using Named Value pairs. But this seems much more poweful looking for an object match instead. VERY NICE! Thanks Grant!

For the “key matching by value” issue, however, I’ve come to different results. In my experience, the comparison is done how it’s always done in AS: primitve data types are compared by value while composite types are compared by reference. If we use, for example, Strings as key (even if we type them as Objects), the comparison is done by value:

var s1:Object = “string”;

var s2:Object = “string”;

trace(“s1==s2:”+(s1==s2));

This is not the case for objects. See this example:

import flash.utils.Dictionary;

var a:Object = { x:3 };

var b:Object = { x:3 };

var c:Object = a;

var s1:Object = “string”;

var s2:Object = “string”;

trace(“a==b:”+(a==b) + ” a===b:”+(a===b));

trace(“a==c:”+(a==c) + ” a===c:”+(a===c));

trace(“s1==s2:”+(s1==s2) + ” s1===s2:”+(s1===s2));

var dict:Dictionary = new Dictionary();

dict[a] = “aaaa”;

dict[b] = “bbbb”; // does not overwrite dict[a] because b’s a different object (comparison by reference)

kglad, I have written a Queue class [doLater] utilizing a Dictionary Object for storage of functions and their parameters. The weak referencing does indeed work. You can find the source for my Queue class here -> http://blog.efnx.com/?p=37 . Using that class in another fla it’s easy to see the functions instantly being gc’d with this code:

“This causes two problems: the reference is immediately available for collection in a weak Dictionary (because while the method is still referenced, the closure object is not), and it can create duplicate entries if you add the same method twice.”

I can demonstrate the first problem. I have seen method (actually closure) keys get garbage collected while the corresponding class instance is still referenced.

But I cannot demonstrate the second problem. I add the same method twice as a key, and I always only get one entry in the Dictionary. Can you provide some code that demonstrates the second problem?

If the second problem is true, then I should never pass a Dictionary instance methods for keys, because I could create duplicate entries (although I’ve never seen that actually happen, at this point.) If only the first problem is true, I can still pass a Dictionary instance methods for keys, as long as I don’t use weak keys. I’d like to know if I really need to stop using Dictionaries with methods (closures) as strongly-referenced keys.

Thanks a lot. While I’m waiting to see if the second problem is true, I thought of a significant consequence of the first problem.

It is impossible to create a passive event-managing utility with a “removeAllEventListeners” function. By “passive”, I mean event listeners are garbage collected in exactly the same circumstances as if the utility did not exist. My reasoning is as follows: In order to implement “removeAllEventListeners”, I need to keep references to all event listener functions, say as keys in a Dictionary. Those references must be weak or strong.

If the keys in the Dictionary are weak, then method closures will be removed from the Dictionary as soon as the garbage collector runs, even if the corresponding event listeners are not garbage collected and can still be triggered. In this case, “removeAllEventListeners” will not work, because it cannot keep references to the event listener functions.

If the keys in the Dictionary are strong, then the corresponding event listeners can always be triggered. The keys in the Dictionary will prevent the event listeners from being garbage collected, even if there are no other references to them and they would have otherwise been garbage collected. In this case, the utility is not passive – it effectively makes all event listeners strongly referenced for as long as there’s a reference to the utility itself.

I’ve tested this idea, and it appears to be correct. Does this sound right to you?

I was wrong. It IS possible to create a passive event-managing utility with a “removeAllEventListeners” function. My incorrect assumption was “I need to keep references to all event listener functions.” Instead, I can keep references to class instances and the String names of their respective methods that are being used as event listener functions. For example, the class instances are keys in a Dictionary, and the values contain method-name Strings. This way, I don’t run afoul of method closures – I use the class instances and method-name Strings to look up a method closure only when I need to remove the event listener.

If the keys in the Dictionary are weak, the class instances will be removed from the Dictionary whenever there are no other references to them and they are garbage collected, that is, in exactly the same circumstances the corresponding event listeners would no longer be triggered if the utility did not exist. So the utility is passive.

“Dave – there’s a very good chance that Adobe has fixed the issue with closures in the past 3 years.”

I can confirm that this bug still exists in Flex 3.5 sdk.

Many of us make a living because Actionscript requires so many workarounds that the average coder is not aware of. However, I draw the line at having to define all my event handlers as public. Dave, you are a stronger man than I!

Can a Dictionary be bound as a datasource for itemRenderer or repeater? I currently use ArrayCollections to fuel the itemRenderer and it works quite well but it sounds like a Dictionary is a more efficient way to handle the data.

“You could cross-reference an array and a dictionary for quick look-ups in ordered lists (ex. a depth manager) – the array would hold references to objects in the appropriate order, and the dictionary would hold array indexes keyed to the objects themselves.”

That’s interesting! Can you give an implementation example? I’m trying to write a class extending the Array, that also contains an Object for quick access to elements by name (no need for a Dictionary, since string are used for keys)… Rewriting the push() and all other methods, so on surface it will look like an array… But got a bit stuck…

Basically want a normal array with length and for loops, but extended with a function getItemByName()

I must be particularly thick, but I’m having trouble wrapping my head around the advantages of using a Dictionary, other than the (debatable) performance buffs.

In an earlier example, you mention using a Dictionary to check objects for something. To me, this has always been possible (with objects built on dynamic classes – which most native, non-primitive types are) by adding a property to the object itself such as “hasBeenChecked”; and if you are the creator of the class you could build that property in as a public property, or probably better, use a private property along with getters (and setters if necessary), and possibly even integrating the “checkObject()” method within the class.

I mention all this simply because I’m trying to find an example of when you would need to iterate over a collection of different types of objects, some of which would not be dynamic classes, whose class source codes you have no control over and which cannot be wrapped into some kind of superclass that could handle the kind of checking you describe.

This is probably all very narrow-minded and I’m sure some really convincing examples of Dictionary usage exist. I was hoping you or one of your readers might point some examples out.

Just been trying to put this to use in Flash CS5, but when looping over using, for in, compiler is complaining like a whore about my key being a string, not an object. I’ve just landed on this prob and either gonna look else where, or make my own type, just wondering if anyone else has this prob and if its just me screwing up my type casting some how!?

Code is simple, init dic add Sprites values using Point types as keys, loop over dic with tmpPoint:Point as key… ect simple stuff…

“Or you could store them in an array – ie checkedObjects.push(someObject) but to see if an object has been checked, you’d need to loop through everything to see if the current one has been checked – unless you give them all a unique index or something.”

I do a check with indexOf(object) before I add complex types to an array. indexOf is the fastest way to access an array in an array if you know what it is you are looking for. It uses strict equality to ensure values are unique, and will return -1 if a value has no index.

Using that I would try to resolve the issue of event listeners and dictionarys by using an array or vector instead. Any time I would need to add a listener I would later want to remove, I can use indexOf to check the vector or array then run whatever code to remove the listener and pop then nullify that reference. Just wonder if that would still lead to a bug with dynamically adding and removing event listeners