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

Brendan Eich brendan at mozilla.com
Fri Dec 16 09:18:47 PST 2011


We are not "giv[ing] up on private names" -- you are really just talking a bit too autodidactically here, frankly.

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.

In implementation terms, and generalizing freely, weak maps take more GC time than private names. This is not (yet) a negligable issue.

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.

So private name objects and weak maps differ observably and in important implementation economics. Both have their uses. You can't get rid of one with the other, not as proposed and not without complexities we're not going to take on.

/be

----- Original Message -----
From: "David Bruant" <bruant.d at gmail.com>
To: "es-discuss" <es-discuss at mozilla.org>
Sent: Friday, December 16, 2011 3:35:53 AM
Subject: Re: Are Private name and Weak Map the same feature? and the Assoc API

There is a paragraph in the original e-mail that I forgot. Adding it below:

Le 16/12/2011 12:19, David Bruant a écrit :
> Hi,
>
> I couldn't post on es-discuss yesterday, so I rewrote my message and
> posted it on github [1]. Here is the markdown source:
>
> # PART 1: The same feature?
> When looked abstractly, both private name and weak maps propose an
> equivalent feature: a mapping between 2 unforgeable references and a value.
> Both allow to share a secret with someone assuming the knowledge of 2
> unforgeable entities.
> Both have the interesting property of symmetric non-discoverability:
>
> * Given an object, you can't list all private names
> * Given a private name, you can't list all objects which have this name
> as a property
> * Given a weak map, you can't list all objects used as keys
> * Given an object, you can't list all weak maps using this object as key
>
> This can be used in WeakMaps to optimize garbage collection. As it turns
> out, the same thing stands for private names: If nothing holds a
> reference to a private name, all related slots in objects can be
> garbage-collected as well.
>
> There are a couple of differences:
>
> *   A private property can be made non-configurable & non-writable
> *   A private name can refer to an accessor property
>
> I claim that these can be reimplemented by overriding the WeakMap API.
>
> I'm open to discussion on whether there are cases that can be
> implemented with one API and not the other. For the rest of this
> message, I'll assume that it's the same feature with 2 different syntax.
>
>
> # PART 2: A more generic syntax
> Unfortunately, private names and WeakMaps (and maps and sets...) both
> define a special new sort of object to work. What about an API that
> would allow to associate any 2 objects and bind a "secret" value to the
> association?
>
> `````JavaScript
> // In one part of the code
> var o1 = {},
>     o2 = {};
> var a = Assoc(o1, o2);
> a.set(37);
>    
> // ...
> // In another component which has a reference to both o1 and o2
> var myA = Assoc(o1, o2);
> myA.get(); // 37
> `````
>
> In order to unseal a secret associated with 2 objects, you need a
> reference to both, that's it. Exactly like with WeakMaps, exactly like
> with private names.
>
>
> ## Part 2.1: where I pretend I can reimplement WeakMaps with the Assoc API
>
> `````JavaScript
> WeakMap = function(){
>     var weakMapIdentity = {};
>     var presence = {};
>    
>     return {
>         get: function(o){
>             return Assoc(weakMapIdentity, o).get();
>         },
>         set: function(o, val){
>             Assoc(presence, o).set(true);
>             return Assoc(weakMapIdentity, o).set(val);
>         },
>         has: function(o){
>             return !!Assoc(presence, o).get();
>         },
>         delete = function(o){
>             Assoc(presence, o).set(undefined);
>         }
>     }
> }
> `````
>
> Interestingly, 2 identities are required to emulate weakmaps. One for
> the values (weakMapIdentity) and one to consider presence of keys. In my
> opinion, the WeakMap API should be separated into 2 APIs. One with
> get/set and the other with add/remove/has which would find the natural
> name of WeakSet.
>
>
> ## Part 2.2: where I go further and get a bit crazy
>
> Some properties:
>
> *  Assoc() === Assoc // why waste a reference? :-p
> *  Assoc(o) !== o
> *  Assoc(o) === Assoc(o)
> *  Assoc(Assoc(o)) === Assoc(o)
> *  Assoc(o, o) === Assoc(o)
> *  Assoc(o1, o2) === Assoc(o2, o1)
>
> The Assoc API could be extended with any number of arguments. The
> resulting object represents the association of all objects passed as
> arguments.
>
> *  Assoc(o1, o2, o3) === Assoc(Assoc(o1, o2), o3) === Assoc(o1,
> Assoc(o2, o3))
> *  ...and these applies to any number of arguments.
>
> Long story short, the Assoc function only cares about whether or not you
> pass it the right references to unseal the secret.
> And you should not care about passing the objects in the "right order".
> If I want to keep a secret from you, I'll create an unforgeable
> reference; I won't try to "obscure" it by not telling you the order in
> which you should pass the objects to Assoc
>
> Of course, since there is no discoverability of associations, all good
> garbage collection optimizations are kept.
>
>
> With association objects, I think we can have a uniform base to play
> with objects without having to invent new sorts of objects (WeakMaps,
> Sets, Maps, etc.) while keeping the possibility to implement (hopefully
> as efficiently) these abstractions.
I'm not sure we should give up on private names though. They provide a
very efficient syntax for private accessors. They could be considered as 
syntactic sugar of the Assoc API.

Moreover, I think we need a way to create unforgeable tokens which would
be clearer than "Object.freeze({})" or "name.create()". This is very
verbose to represent the creation of a token. What about some grawlix-y
syntax for that? {*}


> I've had some comments from Erik Corry on Twitter.
> [2] "Can you add a private property to a frozen object?"
> => This is not discussed in the proposal [4]. I would guess not. It may
> be a difference indeed between WeakMaps and private names, but I think
> it'd be possible to enhance the WeakMap API to allow either that a
> weakmap stops accepting keys or that an object is banned from all
> weakmaps (which are 2 different view of non-extensibility)
> I forgot to say that the Assoc API was a first shot and of course some
> additional primitives may be handy. This is what I'd like to explore.
>
>
> [3] "For private names you can make a polyfill based on ES5
> non-enumerability and random strings. Can u do that with Assoc?"
> => The polyfill would be only partial, because properties would appear
> anyway with Object.getOwnPropertyNames which defeats the purpose of
> private names.
> Moreover, there would always be a risk of collision (which can't happen
> with private names thanks to the unforgeability property).
> Private names have been added because they add something that lack to
> the language. The Assoc API would do the same and any polyfill could
> only be partial (same goes for WeakMaps)
>
> David
>
> [1] https://gist.github.com/1483744
> [2] https://twitter.com/#!/erikcorry/status/147589242246275073
> [3] https://twitter.com/#!/erikcorry/status/147588955611729920
> [4] http://wiki.ecmascript.org/doku.php?id=harmony:private_name_objects

_______________________________________________
es-discuss mailing list
es-discuss at mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


More information about the es-discuss mailing list