Are Private name and Weak Map the same feature? and the Assoc API

David Bruant bruant.d at gmail.com
Fri Dec 16 11:52:13 PST 2011


Le 16/12/2011 18:18, Brendan Eich a écrit :
> We are not "giv[ing] up on private names" -- you are really just talking a bit too autodidactically here, frankly.
Indeed. What I meant was "I do not mean that private names should be
given up". French does not have a passive form (or at least it's rarely
used) and a generic "we" ("on") is often used instead. Sorry for the
confusion.

> Private names and weak maps are observably different in ES.next as proposed. One example: proxies, where accesses of private-named properties trap with a public-name counterpart substituted for the private name object key or identifier.
I agree, this is a major difference and I don't see any way to
reconciliate with weak maps.


However, I have questions and concerns about the public counterpart.
Why does it exists? (there are very few words on it on the wiki and no
link to previous discussion) Is it only to "prevents unintended leakage
of the private name [to proxies]" as said in the wiki or is there
another use case?

It seems to me that the current design of private names prevent easy
composition of proxies.
Let's say we have two attenuators (proxies which reduce your authority
over a given object) constructors we'd like to compose: makeAttenuated1
and makeAttenuated2
-----
// assuming we have an object 'o' and a private name 'p'
var aao = makeAttenuated2(makeAttenuated1(o));
aao[p] = 37;
-----
The 'set' trap of the attenuator2 is called with p.public as name. Then,
this attenuator cannot pass p.public to the attenuator1 proxy as a name
since p.public is not a name object (for good reasons). Should it create
an internal dictionnary between public names and associate new private
names to pass the to second attenuator? It seems that this doesn't scale
very well.

Also, what if I actually want to give the private name to the proxy?
Imagine I use 2 private names on a target, I hand you only the proxy and
one private name (I don't share the other because I don't trust you
enough). You can't unseal the secret unless I share with you an
additional secret which is a public -> private dictionary.
A dictionary sounds costly to create each time I create a proxy. Also,
since I have limited trust in you, I kept with me the second private
name, so there was no "unintended leakage".


I think it would be interesting to have further explanations about "When
proxy traps are invoked for a private name, they receive the name’s
|.public| property instead of the name itself. This prevents unintended
leakage of the private name, but still identifies the name to code that
already has access to it."
As I said in the original e-mail, a private name does not carry any
authority as long as the entity who has it does not have a reference to
any object you have hidden something with this name. It does not seem to
be that big of a deal to give a private name to a proxy as long as you
don't give the second secret.

And if you do not trust an object, just recreate a name. It sounds
cheaper than when you need to create and pass dictionnaries whenever you
need a limited trusted party to get some work done.


Is there a use case requiring the .public part?


> In implementation terms, and generalizing freely, weak maps take more GC time than private names. This is not (yet) a negligable issue.
I'll make a pretentious claim which is: weak maps cannot be more
expensive than private names. If private names are cheaper, you can
always (internally) implement weakmaps as:
-----
function WeakMap(){
    var n = new Name();

    return {
        get: function(o){
            return o[n];
        },
        set: function(o, val){
            o[n] = val;
        },
        has: function(o){
            return n in o;
        },
        delete: function(o){
            delete o[n];
        }
    }
}

WeakMap = function(){
    var n = new Name();

    return {
        get: function(o){
            return o[n]
        }

        set: function(o, val){
            o[n] = val;
        }
    }
}

-----
WeakMaps are currently probably more expensive because they are
implemented "as WeakMaps" (and because apparently, SpiderMonkey's
garbage collector has some quadratic behaviors [1]).

If it's cheaper to add a private property to the objects, why not
implement weak maps this way? It works the other way too: if WeakMaps
are cheaper for other engines, implement your private names as weak maps!


> In ES.next you can set a writable property named by a private name object key to a new value even if the containing object is frozen. Same for a property implemented by transposed set of a weak map indexed by the containing object (the map reference is the analogue of the property private-name-object key).
>
> However: you cannot extend a non-extensible containing object by adding a private-named property. With weak maps, on the other hand, you may freely "add" weak map entries indexed by frozen objects.
I agree that the intentions of weak map and private names are different,
but it would be pretty easy to override WeakMap.prototype.set to forbid
the use of frozen (or whatever filtering rule you wish) objects as keys.
If monkey patching is not beautiful, it's always possible to create an
abstraction on top of WeakMaps for this exclusing feature.

I agree that the intentions are of both features different, but for this
particular example it is a cosmetic difference since the limitation on
private names could be emulated on weak maps or an abstraction on top of it.

> So private name objects and weak maps differ observably
I think the only strong difference is the .public and I'd like to reopen
the debate on this feature since it seems to prevent legitimate use
cases especially under the light that now, the "forwarding proxy"
pattern is first-class and it seems natural to share private names with
parties I trust (especially if I have created the proxy myself).

> and in important implementation economics.
I'm sorry, but I have to ask for a proof of this. I have polyfilled
WeakMaps using private names in 10 lines of JS (engine internals go over
the "don't add properties to frozen object" constraints which I can't in
JavaScript). Whichever is cheaper for any engine could be used as a base
implementation for both features.
I don't see how both feature "differ in important implementation
economics". They only do in the choices you made.

David

[1] https://bugzilla.mozilla.org/show_bug.cgi?id=657264#c1
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20111216/27ad241a/attachment.html>


More information about the es-discuss mailing list