WeakMaps question ?

# Irakli Gozalishvili (14 years ago)

I really need to know why WeakMaps don't accept primitives as keys, can anyone please reply ?

Thanks!

Irakli Gozalishvili Web: www.jeditoolkit.com Address: 29 Rue Saint-Georges, 75009 Paris, France (goo.gl/maps/3CHu)

# Eric Jacobs (14 years ago)

Irakli Gozalishvili wrote:

I really need to know why WeakMaps don't accept primitives as keys, can anyone please reply ?

How would the GC know when to remove the entry from the map? Because a primitive is never (or always, if wrapped) eligible for garbage-collection, a WeakMap does not help your use case.

A WeakMap will not give you your time-limited cache. You still have to implement that yourself.

# Kris Kowal (14 years ago)

On Fri, Nov 11, 2011 at 3:28 PM, Irakli Gozalishvili <rfobic at gmail.com> wrote:

I really need to know why WeakMaps don't accept primitives as keys, can anyone please reply ?

It’s because WeakMaps are intended to drop values if the key is garbage collected.

A WeakMap guarantees that it will drop its value if it becomes provably inaccessible.

This works for non-primitive keys because we can guarantee that once an object has been garbage collected, no future object can be created that would have been identical to it, making the value inaccessible.

Once a primitive value like 1 or the string "abc" has been garbage collected, it is trivial to construct a new value that is identical to the original key, so we could never implicitly garbage collect the value corresponding to a primitive key.

Mark Miller has proposed a strong variation of WeakMap, simply Map, that would serve well in cases where items are explicitly collected.

harmony:simple_maps_and_sets

As I recall, a variant of Map was considered in the ES4 timeline as well.

Kris Kowal

# Oliver Hunt (14 years ago)

A weak map can only remove an entry if both the key and value have died, in many ES implementations a number of the primitives are not gc allocated and so can never die, or are cached globally so have lifetime unrelated to any given program.

The net effect of allowing such primitive values to be used as keys would be to make the map "strong" and the associated values would not be able to be collected.

# Irakli Gozalishvili (14 years ago)

I think what I need is a map with primitive keys and non-null object values, entries of which can be removed & GC-ied if values are no longer referenced. If I understand Map / Set / WeakMap proposals non of them can be used to solve this issue or do I miss something ?

-- Irakli Gozalishvili Web: www.jeditoolkit.com Address: 29 Rue Saint-Georges, 75009 Paris, France (goo.gl/maps/3CHu)

# Allen Wirfs-Brock (14 years ago)

On Nov 11, 2011, at 3:39 PM, Oliver Hunt wrote:

A weak map can only remove an entry if both the key and value have died, in many ES implementations a number of the primitives are not gc allocated and so can never die, or are cached globally so have lifetime unrelated to any given program.

Yes, but this isn't just an implementation decision. The primitive values have existential identify (my term, philosophers may mean something else). All such values conceptually exist for all time, regardless of whether or not an instance of a particular value is actually instantiated an any particular point in time.

# Russell Leggett (14 years ago)

On Nov 11, 2011, at 6:55 PM, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:

On Nov 11, 2011, at 3:39 PM, Oliver Hunt wrote:

A weak map can only remove an entry if both the key and value have died, in many ES implementations a number of the primitives are not gc allocated and so can never die, or are cached globally so have lifetime unrelated to any given program.

Yes, but this isn't just an implementation decision. The primitive values have existential identify (my term, philosophers may mean something else). All such values conceptually exist for all time, regardless of whether or not an instance of a particular value is actually instantiated an any particular point in time.

Regardless of the implementation of primitive values, couldn't we say that the semantics of a weak map ignore primitive keys and look only at the value. Primitive keys are exceptionally common for maps, and this would open up a lot of potential uses, especially regarding caching.

# Mark S. Miller (14 years ago)

On Fri, Nov 11, 2011 at 3:55 PM, Allen Wirfs-Brock <allen at wirfs-brock.com>wrote: [...]

Yes, but this isn't just an implementation decision. The primitive values have existential identify (my term, philosophers may mean something else). All such values conceptually exist for all time, regardless of whether or not an instance of a particular value is actually instantiated an any particular point in time.

I agree, but I would explain the distinction differently. In a memory safe object language such as JS with GC and without destructors or finalizers, I would say that all values, both primitives and objects, "conceptually exist for all time, regardless of whether or not an instance of a particular value is actually instantiated an any particular point in time." However, some values may no longer be reachable from live computation -- which is why the garbage collector can deallocate these unobservably (modulo resource usage and limits).

Rather, I would divide up values into those which

  1. have an unforgeable unique identity associated with a unique act of creation. Direct access to these are "access limited" rather than "knowledge limited" -- you only obtain direct access if something that already has direct access to it (and to you) gives it to you.
  2. are synthesizable from the identical ingredients. Access to a synthesizable object is "knowledge limited" rather than "access limited" -- given its ingredients (which may themselves be unforgeable), you can obtain access to a synthesizable object if you know or can guess how these ingredients are arranged.

In JS today, this distinction is even clearer because all synthesizable values are fully synthesizable all the way down -- they contain no unforgeable ingredients. I refer to fully synthesizable values as "data". By contrast, given unforgeable x and y, in HOBD, #[x, y] would be a synthesizable pair of x and y, which is synthesizable by anyone with direct access to x and y and the knowledge to arrange them again in this manner. This pair is synthesizable but not fully synthesizable.

A WeakMap preserves this unobservability by only collecting associations whose keys can no longer be reached from live computation. The garbage collector cannot feasibly determine that a fully synthesizable value will not be re-synthesized, and so could never collect these. Since the purpose of a WeakMap is to avoid unbounded leakage, were it to accept fully synthesizable keys, it would need to retain those associations forever, creating a hard to debug infinite memory leak. Better to reject quickly, to give an informative diagnostic early.

An open question is whether WeakMaps should accept synthesizable containers of unforgeable ingredients, such as the above #[x, y], since it knows that, for example, once x is no longer reachable, then it is no longer possible to re-synthesize #[x, y]. Once x has been collected, this pair has also become unreachable. We'll cross that bridge when we come to HOBD.

# Allen Wirfs-Brock (14 years ago)

On Nov 12, 2011, at 5:10 AM, Russell Leggett wrote:

Regardless of the implementation of primitive values, couldn't we say that the semantics of a weak map ignore primitive keys and look only at the value. Primitive keys are exceptionally common for maps, and this would open up a lot of potential uses, especially regarding caching.

What you are asking for is a "weak array" (or an array of "weak references"). While some people think that such things have utility others are concerned that they expose GC based non-determination which they don't want to allow into the language.

# Brendan Eich (14 years ago)

On Nov 12, 2011, at 9:19 AM, Allen Wirfs-Brock wrote:

On Nov 12, 2011, at 5:10 AM, Russell Leggett wrote:

Regardless of the implementation of primitive values, couldn't we say that the semantics of a weak map ignore primitive keys and look only at the value. Primitive keys are exceptionally common for maps, and this would open up a lot of potential uses, especially regarding caching.

What you are asking for is a "weak array" (or an array of "weak references"). While some people think that such things have utility others are concerned that they expose GC based non-determination which they don't want to allow into the language.

WeakRef != WeakMap, we keep running into confusion between the two.

WeakRefs are useful for systems-builders. They should not be exposed to unprivileged code. Is there an object-capability security model that would work on the web, by which "frameworks" with some higher degree of trust could be introduced to WeakRef as a capability, while ordinary web content could not access WeakRef at all? I don't know of such a model, but perhaps Mark has ideas.

# Mark S. Miller (14 years ago)

On Sat, Nov 12, 2011 at 11:56 AM, Brendan Eich <brendan at mozilla.com> wrote:

WeakRef != WeakMap, we keep running into confusion between the two.

WeakRefs are useful for systems-builders. They should not be exposed to unprivileged code. Is there an object-capability security model that would work on the web, by which "frameworks" with some higher degree of trust could be introduced to WeakRef as a capability, while ordinary web content could not access WeakRef at all? I don't know of such a model, but perhaps Mark has ideas.

Allen and Brendan are exactly correct about the distinction. I did write a WeakRef strawman at < strawman:weak_references>. The rest

of that strawman is not in great shape. Since it was never on the table for consideration in the ES.next timeframe, I have not really maintained it. Allen's message is in terms of "weak arrays" rather than individual weak references. Experience with Smalltalk suggests that this may make things much lighter on an implementation without any significant inconvenience for the normal uses cases. Allen can explain this further if he wishes. This is a difference in how things are aggregated, rather than any real difference on fundamental issues.

In agreements with Brendan's next point, that strawman says:

Note that makeWeakPtr is not safe for general access since it grants access

to the non-determinism inherent in observing garbage collection. The resulting side channel reveals information that may violate the confidentiality assumptions strawman:gc_semantics < strawman:gc_semantics#confidentiality

of other programs.

Previous ocap languages have faced this issue < www.combex.com/papers/darpa-review/security-review.html>, <

www2.fiit.stuba.sk/~kosik/tamed-pict.html>, <

www.hpl.hp.com/techreports/2006/HPL-2006-116.html>, and I think the

patterns discovered by their solutions can be adapted to the web. I do have further thoughts about this starting with < lists.squeakfoundation.org/pipermail/squeak-e/2003-February/000027.html>, < lists.squeakfoundation.org/pipermail/squeak-e/2003-February/000028.html>,

but I think I'll wait until I have a better feel for how the ES-next module loaders should be used in practice before trying to sketch anything concrete.