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

David Bruant bruant.d at gmail.com
Fri Dec 16 03:35:53 PST 2011


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



More information about the es-discuss mailing list