jashkenas / underscore

JavaScript's utility _ belt
https://underscorejs.org
MIT License
27.3k stars 5.53k forks source link

Consider switching memoize cache to be compatible with ES6 Map/WeakMap. #1862

Open jdalton opened 10 years ago

jdalton commented 10 years ago

At the moment the _.memoize cache is just a plain object. If we were to switch it to being a simple wrapper around the cache object (still doing the same param to string key use) but with the interface of ES6 Map, WeakMap that would allow devs to swap in ES6 Maps/WeakMaps for their cache. The thin wrapper would have an interface to mimic Map/WreakMap, so has, set, get, and optionally (delete, clear).

_.memoize could have a Cache constructor bolted on to it _.memoize.Cache to allow devs to swap it out with a Map/WeakMap or equiv shim as well.

Map/WeakMap are available on all modern browsers, node --harmony.

Thoughts?

joshuacc commented 10 years ago

WreakMap

Freudian slip? ;-)

jdalton commented 10 years ago

LOL, Imma keep it :grinning:

akre54 commented 10 years ago

I'm a tenuous thumbs down on this. Underscore isn't a Maps library and this would be quite a rabbit hole to go down. It might be something to explore in 2.0 or 3.0 however, depending on how much code it would add.

jdalton commented 10 years ago

I'm a tenuous thumbs down on this. Underscore isn't a Maps library and this would be quite a rabbit hole to go down.

I'm not saying Underscore should implement anything more than its simple cache look up as it is now. I'm suggesting it wrap it with an interface that is compatible with ES6 Map/WeakMap to allow devs to swap them out.

Related to #1841.

akre54 commented 10 years ago

sounds reasonable. might be nice to add support for a few other modern features for 2.0 too.

joshuacc commented 10 years ago

I'm :+1: on this one.

megawac commented 10 years ago

How would the fallback work? Should we change it to using an array

jdalton commented 10 years ago

How would the fallback work? Should we change it to using an array

There would be no fallback. We don't change the existing value -> use as key (coerce to string) behavior. This way it's consistent in old and new environments. By adopting an interface of Map/WeakMap we allow devs to use them or shims without having to implement a complex map implementation on our end.

For exampe devs could do _.memoize.Cache = WeakMap; and _.memoize wouldn't care. It'd be all "Oh the _.memoize.Cache constructor returns a cache object with the interface I'm expecting (has, set, etc)" and would use it just as it would the basic Cache object.

It could look something like:

function Cache() {
  this.__wrapped__ = {};
}
_.extend(Cache.prototype,
  get: function(key) {
    return this.__wrapped__[key];
  },
  has: function(key) {
    return _.has(this.__wrapped__, key);
  },
  set: function(key, value) {
    this.__wrapped__[key] = value;
    return this;
  }
});

_.memoize = function(func, hasher) {
  var memoize = function(key) {
    var cache = memoize.cache;
    var address = (hasher ? hasher.apply(this, arguments) : key);
    if (!cache.has(address)) cache.set(address, func.apply(this, arguments));
    return cache.get(address);
  };
  memoize.cache = new _.memoize.Cache;
  return memoize;
};

_.memoize.Cache = Cache;
bnjmnt4n commented 10 years ago

:+1:

jgonggrijp commented 4 years ago

~Maybe depends on #2453.~

Edit: no, it doesn't.

jgonggrijp commented 2 years ago

2.0 Should just use Map internally. No need for fancy wrappers.