Skip to content

Instantly share code, notes, and snippets.

@DavidBruant
Created December 16, 2011 00:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save DavidBruant/1483744 to your computer and use it in GitHub Desktop.
Save DavidBruant/1483744 to your computer and use it in GitHub Desktop.
Are Private name and Weak Map the same feature? and the Assoc API

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?

// 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

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);
        }
    }
}

I feel that "presence" shouldn't be there and the WeakMap API should be kept to get and set.

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment