google / traceur-compiler

Traceur is a JavaScript.next-to-JavaScript-of-today compiler
Apache License 2.0
8.18k stars 580 forks source link

Collections unit tests (for Map, Set, WeakMap, WeakSet) #898

Open DmT021 opened 10 years ago

DmT021 commented 10 years ago

I wrote not bad (I believe) polyfill for ES6 Collections for Traceur. It provides really Weakness and O(1) complexity (in most cases). Can someone give me unit tests for Map, Set, WeakMap, WeakSet? In the best case, it should include tests for frozen(sealed or with preventExtensions called) objects as well as simple objects. Or Traceur doesn't want polyfills for collections?

rwaldron commented 10 years ago

It provides really Weakness

I'm curious to see how this is implement since it's not possible to know if the only reference to an object key is the key itself.

DmT021 commented 10 years ago

I'll publish it as soon as I will be sure that it works correct. I just want check it with unit tests.

P.S. Proof of weakness 2014-03-21 19 47_

johnjbarton commented 10 years ago

Unfortunately for software developers everywhere, unit tests are vitally important and often more difficult to produce than library software. In fact many libraries are more important for their test case completeness and quality than the implementation features they provide. Creating your own unit tests will be essential.

arv commented 10 years ago

The problem is that true WeakMaps cannot be written in ES5. Cycles between key/values in the map cannot be detected.

For Polymer we implemented WeakMap as well and as long as there are no cycles, expandos works well enough. However, we found the constant for the O(1) solution to be very high and we tweaked and tweaked our solution since the wm was a bottle neck for us. See https://github.com/Polymer/WeakMap/blob/master/weakmap.js for our final code. Notice that it is not even trying to actually hide the key like a lot of other solutions do. Performance of the WeakMap is really crucial.

DmT021 commented 10 years ago

I commited my implemetation of collections to my fork. See it at https://github.com/DmT021/traceur-compiler/tree/master/src/runtime/polyfills It's a bit complex, but I can explain how it works if someone needed.

DmT021 commented 10 years ago

Today I updated my sources. Now implemetation works with following comlexity: get - O(1), set - O(1), has - O(1), delete - O(1), clear - O(1). (clear much improved). It also stores less data inside collection (only values now). And it is stil weak. More proofs of weakness:

var WeakMap = System.get('traceur-runtime@0.0.31/src/runtime/polyfills/WeakMap').WeakMap;

var length = 1e5;
var wm = new WeakMap(),
    container = [];

function fillContainer() {
    for (var i = 0; i < length; i++) {
        container.push({
            'dummyProperty': 'dummyValue' + i
        });
    }
}

function fillWeakMap() {
    for (var i = 0; i < length; i++) {
        wm.set(container[i], i);
    }
}

function clearContainer() {
    for (var i = 0; i < length; i++) {
        container[i] = undefined;
    }
}

function alltest() {
    (function () {
        fillContainer();
        fillWeakMap();
        clearContainer();
    })();
}

Internet Explorer 11 2014-03-24 18 49 34 Firefox 2014-03-24 18 49 57 Chrome 2014-03-24 18 50 02 @arv Questions about your implementation: Where is clear method? Why do you need to store key in key[%weakmap_name%][0]? Why your implemetation stores values directly in keys (so values can not be collected till keys are alive, even if weakmap was collected)?

arv commented 10 years ago

For Polymer we didn't need clear.

The Polymer implementation uses expandos on the key but when you use expandos you need to make sure you are not getting the property from the prototype. The classic way to do this is to just use hasOwnProperty but that is slow in most engines today because it has not been optimized. Using an array containing the key we could just do a === check which is highly optimized in all engines.

It is true that the Polymer impl is not very weak at all but our use case was for side tables (it was even called SideTable for the longest time) where the key is the thing that we want to act as gc owner anyway.