On Wed, Jan 18, 2012 at 11:07 AM, Jason Orendorff <span dir="ltr"><<a href="mailto:jason.orendorff@gmail.com">jason.orendorff@gmail.com</a>></span> wrote:<div>[...]</div><div><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

The result of the discussion linked above was the introduction of<br>
collections.defaultdict to the Python standard library:<br>
  <a href="http://docs.python.org/library/collections.html#defaultdict-objects" target="_blank">http://docs.python.org/library/collections.html#defaultdict-objects</a><br>
<br>
To me, defaultdict was a relief, and long overdue. It solved all three<br>
problems with setdefault. I've been using it happily ever since. Ruby<br>
has a similar feature built into its core Hash type.<br></blockquote><div><br></div><div>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.</div>
<div><br></div><div>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.</div>
<div><br></div><div>Everyone on this thread, is there any need expressed in this thread that is not satisfied by InfiniteMap?</div><div><br></div><div><div><br></div><div>function InfiniteMap(baseMap, lazyFactory) {</div>
<div>  "use strict";</div><div><br></div><div>  var pumpkin = Object.freeze(Object.create(null)); // should not escape</div><div>  var tombstone = Object.freeze(Object.create(null)); // should not escape</div><div>
<br></div><div>  return {</div><div>    get: function(key, defaulValue /*= void 0*/) {</div><div>      var result = baseMap.get(key, pumpkin);</div><div>      if (result === pumpkin) {</div><div>        result = lazyFactory();</div>
<div>        baseMap.set(key, result);</div><div>        return result;</div><div>      }</div><div>      if (result === tombstone) { return defaultValue; }</div><div>      return result;</div><div>    },</div><div>    has: function(key) {</div>
<div>      return baseMap.get(key, pumpkin) !== tombstone;</div><div>    },</div><div>    set: baseMap.set.bind(baseMap),</div><div><br></div><div>    'delete': function(key) {</div><div>      baseMap.set(key, tombstone);</div>
<div>    }</div><div>  };</div><div>}</div></div><div><br></div></div>
</div>