A different semantics for WeakMap#get default value

Mark S. Miller erights at google.com
Wed Jan 18 22:51:41 PST 2012

On Wed, Jan 18, 2012 at 11:07 AM, Jason Orendorff <jason.orendorff at gmail.com
> wrote:

> The result of the discussion linked above was the introduction of
> collections.defaultdict to the Python standard library:
>  http://docs.python.org/library/collections.html#defaultdict-objects
> To me, defaultdict was a relief, and long overdue. It solved all three
> problems with setdefault. I've been using it happily ever since. Ruby
> has a similar feature built into its core Hash type.

Hi Jason, I like the idea that the Python defaultdict seems almost to be,
which I'll call an InfiniteMap. For JS, the following InfiniteMap actually
obeys the Map contract while implementing a Map with an infinite number of
key-value mappings. It's initial state is total -- it provides a mapping
for every key, and so, in this initial state, infMap.has(key) would always
return true. It does this by using the lazyFactory function as needed to
make the infinite population of values initially associated with each of
the infinite population of keys.

Because an instance of InfiniteMap conforms to the full Map contract (given
that baseMap does and is not otherwise used), we have full Liskov
substitutability -- you can validly pass an InfiniteMap to an abstraction
expecting a Map. If baseMap and lazyFactory are well behaved, including
having no externally observable side effects, then although the get()
method below internally causes a side effect, get() does not observably
cause any side effects. For all observations possible by a client of a well
behaved InfiniteMap instance, get() remains a pure query operation.

Everyone on this thread, is there any need expressed in this thread that is
not satisfied by InfiniteMap?

function InfiniteMap(baseMap, lazyFactory) {
  "use strict";

  var pumpkin = Object.freeze(Object.create(null)); // should not escape
  var tombstone = Object.freeze(Object.create(null)); // should not escape

  return {
    get: function(key, defaulValue /*= void 0*/) {
      var result = baseMap.get(key, pumpkin);
      if (result === pumpkin) {
        result = lazyFactory();
        baseMap.set(key, result);
        return result;
      if (result === tombstone) { return defaultValue; }
      return result;
    has: function(key) {
      return baseMap.get(key, pumpkin) !== tombstone;
    set: baseMap.set.bind(baseMap),

    'delete': function(key) {
      baseMap.set(key, tombstone);
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20120118/32d4d3e5/attachment.html>

More information about the es-discuss mailing list