Tuesday, March 11, 2014

How Dictionary Works in Flex

All of us have used Dictionary in Flex. This is supposed to be HashMap alternative in Flex. As per the documentation:
"You can use the Dictionary class to create an associative array that uses objects for keys rather than strings. Such arrays are sometimes called dictionaries, hashes, or maps."

We cannot say that it is implemented exactly in way the HashMap is implemented in Java. Actually we don't know as we cannot check its source code. But we can say one thing that it is very well implemented and it takes O(1) for all operations and it is reasonably fast. We can use the following benchmark taken from Stack Overflow page.
package  {
    import flash.display.Sprite;
    import flash.text.TextField;
    import flash.utils.*;
    public class Benchmark extends Sprite {

        public function Benchmark() {
            var txt:TextField = new TextField();
            this.addChild(txt);
            txt.text = "waiting ...";
            txt.width = 600;        
            const repeat:int = 20;
            const count:int = 100000;
            var d:Dictionary = new Dictionary();
            var j:int, i:int;
            var keys:Array = [];
            for (j = 0; j < repeat * count; j++) {
                keys[j] = { k:j };
            }
            setTimeout(function ():void {
                var idx:int = 0;
                var out:Array = [];
                for (j = 0; j < repeat; j++) {
                    var start:int = getTimer();
                    for (i = 0; i < count; i++) {
                        d[keys[idx++]] = i;
                    }
                    out.push(getTimer() - start);
                }
                txt.appendText("\n" + out);
                start = getTimer();
                for (var k:int = 0; k < i; k++) {
                    test();
                }
                txt.appendText("\ncall:"+(getTimer() - start));
                idx = 0;
                out = [];
                for (j = 0; j < repeat; j++) {
                    start = getTimer();
                    i = 0;
                    for (i = 0; i < count; i++) {
                        delete d[keys[idx++]];
                    }               
                    out.push(getTimer() - start);
                }
                txt.appendText("\n" + out);
            },3000);//wait for player to warm up a little
        }
        private function test():void {}
    }
}

Also HashMaps in java makes use of hashCode() method whereas Dictionary makes use of strict equality (= = = ) of keys and so using object as keys can be a problem in it.

A related aspect is we can also use object to have similar functionality:
var obj:Object = new Object();
obj.something = "something";

var dict:Dictionary = new Dictionary();
dict.something = "something";

trace(obj.something, dict.something);
Then what is the difference? Actually if we are planning to use String keys there is no need for Dictionary class. Though I personally feel that the time of O(1) can still be questionable.

One more point to observe as explained here is:
The dictionary[key] does NOT necessarily return the same value as dictionary["key"], even if key.toString() equals "key". However, object[key] will return the same value as object["key"], if key.toString() equals "key".
We cannot make a Dicitonary Bindable. We can find some workaround though: wrapping it in ObjectProxy etc.

Another aspect while using Dictionary to store objects is Memory Management. As mentioned in doc:
"As long as any reference to the object exists, the garbage collection system will not recover the memory that the object occupies. If the value of myObject is changed such that it points to a different object or is set to the value null, the memory occupied by the original object becomes eligible for garbage collection, but only if there are no other references to the original object."

So if we set object to null first and then delete from dictionary it will not work. When we set the object to null it does not clear the reference to this in Dictionary so we will not get what we need.
valueObject = null;
delete myMap[valueObject];

But if we reverse the order it will work properly. More here.

No comments: