Weak event listener

# Marius Gundersen (11 years ago)

I tried posting this before, but it seems to have gotten lost on the internet.

One thing which is impossible to make in JavaScript today is a weakly referenced event listener system. In such a system an event listener is not strongly referenced by the event system, so events are only dispatched to it as long as another object holds a reference to it. For example:

//some weak event system, could be global or created with constructor var events = new WeakEventSystem();

(function(){ //This object only exists inside this IIFE, not outside it var myObject = { handler: function(event){ console.log("handle event: " + event); } };

//add a listener to events, but events only has a weak reference to it
events.addEventListener("someEvent", myObject.handler);

//the following causes the handler above to be called, resulting in

output on the console events.dispatchEvent("someEvent", {params:"someParams"});

})();

//myObject does not exist anymore //the following does not output anything on the console events.dispatchEvent("someEvent", {params:"someParams"});

In this example the event system does not hold a strong reference to the listener/handler function, so if nothing else has a reference to the handler function, it is garbage collected.

Any thoughts on this, as an alternative to the more general (and low level) weak references?

Marius Gundersen

# Kevin Gadd (11 years ago)

Most use cases I've personally seen for weak events would be satisfied by a WeakMap of weak event target -> event handler. Having the event handler

itself be weak instead of the event target seems strange to me; it introduces a bunch of nondeterministic behavior that isn't desirable - sometimes you'll free all your references to a handler and it'll fire anyway, because it hasn't been collected. It also introduces the potential for accidentally freeing all your references to a handler and having important behavior not run. If you get proper WRs this should be pretty easy to build if you want it.

I think the fact that this would make GC behavior observable through the execution/non-execution of event handlers probably makes it some sort of security hole in the same way that WRs are, but I'm not sure - I've never fully understood the threat posed by that information leak.

# Erik Arvidsson (11 years ago)

WeakMap would not work in this specific case since a WeakMap cannot be iteratered.

WeakRefs are needed to do data binding and pub sub systems like these. WeakRefs are very likely to be part of ES7. We haven't really talked much about them formally but informally TC39 members seems to agree.

strawman:weak_refs

# Peter Michaux (11 years ago)

On Mon, Mar 25, 2013 at 2:55 AM, Marius Gundersen <gundersen at gmail.com> wrote:

One thing which is impossible to make in JavaScript today is a weakly referenced event listener system. In such a system an event listener is not strongly referenced by the event system, so events are only dispatched to it as long as another object holds a reference to it.

Being able to make an observable subject that keeps a weak list of observers would be very useful to ease memory management within an application and avoid accidental memory leaks at the application level. Sometimes the application programmer may forgot to remove a observer from an observable subject, for example.

With regard to the MVC architecture, this could be the best addition to the language to make application development easier. A view might mistakenly not unsubscribe from its associate model when the view is destroyed, for example. That or the view's destroy method is never even called because the application programmer forgot to call it.

Peter

# Benoit Marchant (11 years ago)

Very true, I'm wondering if based on usage today it could make sense to have this as default behavior on current API?

Benoit

# Marius Gundersen (11 years ago)

So to summarize:

  • This would be very useful in large MVC applications with many independent components.
  • Even with WeakMaps there is no way to implement weak event listeners, since WeakMaps cannot be iterated. A weak reference implementation would solve this.
  • The main problem with weak event listeners is that they are not deterministic; even if you remove all references to an object there is no way to ensure that the object is garbage collected immediately, and so events would still be dispatched to it for an indeterminable period of time after the last strong reference is severed. I'm not sure of how big of a problem this would be; it might be an annoyance or it might break the application completely.

Marius Gundersen

# Juan Ignacio Dopazo (11 years ago)

2013/3/25 Erik Arvidsson <erik.arvidsson at gmail.com>

WeakMap would not work in this specific case since a WeakMap cannot be iteratered.

I thought there was an iterable WeakSet for ES6. Was it postponed to ES7 or just dropped?

Thanks, Juan

# Tom Van Cutsem (11 years ago)

2013/3/26 Juan Ignacio Dopazo <dopazo.juan at gmail.com>

2013/3/25 Erik Arvidsson <erik.arvidsson at gmail.com>

WeakMap would not work in this specific case since a WeakMap cannot be iteratered.

I thought there was an iterable WeakSet for ES6. Was it postponed to ES7 or just dropped?

I doubt there was ever an iterable WeakSet proposal, since iteration would make GC of the weakly held values observable. This is exactly the same reason why WeakMap isn't iterable.

# Rick Waldron (11 years ago)

On Tue, Mar 26, 2013 at 9:46 AM, Tom Van Cutsem <tomvc.be at gmail.com> wrote:

2013/3/26 Juan Ignacio Dopazo <dopazo.juan at gmail.com>

2013/3/25 Erik Arvidsson <erik.arvidsson at gmail.com>

WeakMap would not work in this specific case since a WeakMap cannot be iteratered.

I thought there was an iterable WeakSet for ES6. Was it postponed to ES7 or just dropped?

I doubt there was ever an iterable WeakSet proposal, since iteration would make GC of the weakly held values observable. This is exactly the same reason why WeakMap isn't iterable.

Cheers, Tom

TC39 reached consensus on the inclusion of WeakSet, though it needs to be designed: rwldrn/tc39-notes/blob/master/es6/2012-09/sept-19.md#weakset

Mark Miller proposed semantics for WeakRefs to satisfy security concerns: esdiscuss/2013-January/028542

Both of these should be discussed at the next meeting.

# Domenic Denicola (11 years ago)

From: Rick Waldron [waldron.rick at gmail.com]

TC39 reached consensus on the inclusion of WeakSet, though it needs to be designed: rwldrn/tc39-notes/blob/master/es6/2012-09/sept-19.md#weakset

Is this ES6 timeframe, or ES7? I have run into a few use cases for it since hearing this, and was hoping it was on-track.

Mark Miller proposed semantics for WeakRefs to satisfy security concerns: esdiscuss/2013-January/028542

I assume this is ES7 timeframe, even if it'll be discussed at the next meeting?

# Rick Waldron (11 years ago)

On Tue, Mar 26, 2013 at 12:23 PM, Domenic Denicola < domenic at domenicdenicola.com> wrote:

From: Rick Waldron [waldron.rick at gmail.com]

TC39 reached consensus on the inclusion of WeakSet, though it needs to be designed:

rwldrn/tc39-notes/blob/master/es6/2012-09/sept-19.md#weakset

Is this ES6 timeframe, or ES7? I have run into a few use cases for it since hearing this, and was hoping it was on-track.

The discussion immediately preceding that discussion indicates that WeakSet will be a requirement of Proxy:

rwldrn/tc39-notes/blob/master/es6/2012-09/sept-19.md#proxy-and-private-names

Mark Miller proposed semantics for WeakRefs to satisfy security concerns: esdiscuss/2013-January/028542

I assume this is ES7 timeframe, even if it'll be discussed at the next meeting?

I don't know the answer to this question, sorry.

# Sam Tobin-Hochstadt (11 years ago)

On Tue, Mar 26, 2013 at 12:28 PM, Rick Waldron <waldron.rick at gmail.com> wrote:

On Tue, Mar 26, 2013 at 12:23 PM, Domenic Denicola <domenic at domenicdenicola.com> wrote:

From: Rick Waldron [waldron.rick at gmail.com]

TC39 reached consensus on the inclusion of WeakSet, though it needs to be designed:

rwldrn/tc39-notes/blob/master/es6/2012-09/sept-19.md#weakset

Is this ES6 timeframe, or ES7? I have run into a few use cases for it since hearing this, and was hoping it was on-track.

The discussion immediately preceding that discussion indicates that WeakSet will be a requirement of Proxy:

rwldrn/tc39-notes/blob/master/es6/2012-09/sept-19.md#proxy-and-private-names

Note that this requirement is conditional on a particular approach (which I still favor) to the interaction between proxies and private names, and so since that's still up in the air, the WeakSet requirement for ES6 may go away.

# Mark S. Miller (11 years ago)

WeakSet may or may not happen by ES6. But even if it doesn't, WeakSet is trivially shimmable on WeakMap.

WeakRef will definitely not happen earlier than ES7. I do hope it will happen in ES7, but this discussion has yet to happen.

# Jason Orendorff (11 years ago)

On Mon, Mar 25, 2013 at 9:29 PM, Erik Arvidsson <erik.arvidsson at gmail.com> wrote:

WeakMap would not work in this specific case since a WeakMap cannot be iteratered.

What would work here is determinism: gist.github.com/jorendorff/5245857 For this, a deterministic API is just as easy to use, easier to implement, and easier to reason about.

The main justification I’ve heard for WeakRef is that sometimes it’s hard to unhook observers at the point where you find you don't want them anymore. That’s plausible. I'd really appreciate some better examples of how this comes up and (especially) how WeakRef helps in practice. The References section of the strawman is just a collection of links to reactive libraries like Tangle[1], without elaboration. But if Tangle actually used weak observer semantics, even the most basic Tangle use cases would break! [2]

I don't mean to pick on WeakRef. Across the board, I would love to see better motivating use cases for all proposals: less contrived, and actually illustrating the benefit of the proposal. I don’t think it’s too much to ask.

The modules proposal has suddenly gone from one of the worst-motivated proposals in ES6 to perhaps the best, with scads of excellent use cases. More of that, please!

-j

[1]worrydream.com/Tangle

[2]worrydream.com/Tangle/Examples/CookieExample.js Note that after the observer is hooked up, it immediately becomes unreachable (except via Tangle itself) as soon as that function returns.

# David Bruant (11 years ago)

Le 26/03/2013 20:25, Jason Orendorff a écrit :

On Mon, Mar 25, 2013 at 9:29 PM, Erik Arvidsson <erik.arvidsson at gmail.com> wrote:

WeakMap would not work in this specific case since a WeakMap cannot be iteratered. What would work here is determinism: gist.github.com/jorendorff/5245857 For this, a deterministic API is just as easy to use, easier to implement, and easier to reason about.

I'm not entirely sure I understand your code snippet. Is withListener some equivalent of Node's once [1][2]? If so, then I agree, but, we're back to a debate earlier this month starting at [3] (implicitly forked).

From the previous discussions, my understanding of the problem that weakrefs are expected to solve is automated cascading of GC, that is, a full subgraph gets collected as a result of releasing one reference assuming the convention that everyone with access to the weakref plays nice by always accessing the object via .get, and I guess via releasing the weakref (which is itself an object?) when useless.

I'm still not entirely convinced whether the problem being solved is worth the non-determinism it brings along. I'm starting to wonder whether bringing weakrefs is equivalent to having iterable WeakMaps... And if so, why not make WeakMaps iterable?

The References section of the strawman is just a collection of links to reactive libraries like Tangle[1], without elaboration. But if Tangle actually used weak observer semantics, even the most basic Tangle use cases would break! [2]

The precedent of other languages was used as a justification of doing the same in JS and I guess this example is a good case of why this might not be a good argument. In JS, listeners are functions which are their own objects and keeping one hard reference imposes a different constraint than in other languages.

David

[1] nodejs.org/api/events.html#events_emitter_once_event_listener [2] joyent/node/blob/2eb847849fc133e39d64798bee01252d9f3c4b58/lib/events.js#L169-L182 (the implementation is clean enough to be a good documentation in itself, kudos to the Node folks :-) ) [3] esdiscuss/2013-March/028921

# Brendan Eich (11 years ago)

agree on your request for non-contrived use-cases. I wrote about the general observer pub/sub problem here:

www.mail-archive.com/[email protected]/msg21480.html

Hope it helps. One specific thought below.

Jason Orendorff wrote:

What would work here is determinism: gist.github.com/jorendorff/5245857 For this, a deterministic API is just as easy to use, easier to implement, and easier to reason about.

It seems to me you want some kind of deterministic finalization or scoped destructor. That's not in the cards for JS.

# Allen Wirfs-Brock (11 years ago)

On Mar 26, 2013, at 12:18 PM, Mark S. Miller wrote:

WeakSet may or may not happen by ES6. But even if it doesn't, WeakSet is trivially shimmable on WeakMap.

Which is why it isn't the in the spec. yet. It was introduced in support of Proxy private Symbol white list, but it is still unclear whether we will have them and even if we do, it's not clear that the actual internal whitelist needs to be exposed as a WeakSet.

# Brandon Benvie (11 years ago)

On 3/26/2013 1:03 PM, David Bruant wrote:

I'm starting to wonder whether bringing weakrefs is equivalent to having iterable WeakMaps... And if so, why not make WeakMaps iterable?

This is a question I had as well. An iterable WeakMap is nearly the same as a Map full of WeakRefs, is it not? Just a different API that is less usable for single references and more usable for collections.

# David Bruant (11 years ago)

Le 26/03/2013 21:26, Brandon Benvie a écrit :

On 3/26/2013 1:03 PM, David Bruant wrote:

I'm starting to wonder whether bringing weakrefs is equivalent to having iterable WeakMaps... And if so, why not make WeakMaps iterable? This is a question I had as well. An iterable WeakMap is nearly the same as a Map full of WeakRefs, is it not? Just a different API that is less usable for single references and more usable for collections.

Interestingly, publish-subscribe would probably make a better use of an iterable weakset (set of observers) I think: When a publication happens, what needs to be done is tell all the (remaning) subscribers. I don't think anyone really needs the weakrefs themselves. Iterating over remaining observers seems to be enough.

# Mark S. Miller (11 years ago)

Because the weak-map-maker constructor grants no privilege and can be generally accessible, whereas the weak-ref-maker grants the privilege of being able to observe the non-determinism of GC, and so should not be made accessible to code that shouldn't have such powers. It is the same reason why Maps and Sets, which are enumerable, enumerate their elements in a deterministic order.

In short, separation of concerns as well as separation of privileges.

Those who have access to both a weak-map-maker and a weak-ref-maker can trivially build a non-deterministic enumerable-weak-map-maker if they wish. In fact, at < strawman:weak_references#a_weakvaluemap>

I even show another useful non-deterministic weakish-map-maker (WeakValueMap) whose utility requires observable non-determinism[1], and show how to build it from a weak-map-maker and a weak-ref-maker.

[1] Either that, or I was not clever enough to build something that could serve this purpose without exposing non-determinism. If someone is more clever and does see how to do that, please speak up. Thanks.

# David Bruant (11 years ago)

Le 26/03/2013 21:12, Allen Wirfs-Brock a écrit :

On Mar 26, 2013, at 12:18 PM, Mark S. Miller wrote:

WeakSet may or may not happen by ES6. But even if it doesn't, WeakSet is trivially shimmable on WeakMap.

Set is also shimmable on top of Map. If Set is in, there are as many reason to have WeakSets in. If WeakSets are considered as second class, so should Set. I feel Set and WeakSet fate should be bound.

Which is why it isn't the in the spec. yet. It was introduced in support of Proxy private Symbol white list, but it is still unclear whether we will have them and even if we do, it's not clear that the actual internal whitelist needs to be exposed as a WeakSet.

I don't understand the reluctance towards having WeakSets in spec. They have as much use as WeakMaps. Domenic wrote a couple of messages ago "I have run into a few use cases for [WeakSet] (...), and was hoping it was on-track." I've had a case too and even left a comment about it [1]. We can argue whether, that's a use case more for private symbols than WeakSet, but still, weaksets sounds like an appriopriate tool for appropriate situations.

David

[1] DavidBruant/HarmonyProxyLab/blob/413a153c01b34bfc281b901b399ac09f3ca8c0d7/ES3AndProxy/ES5ObjectModelEmul.js#L57

# David Bruant (11 years ago)

Le 26/03/2013 22:56, Mark S. Miller a écrit :

Because the weak-map-maker constructor grants no privilege and can be generally accessible, whereas the weak-ref-maker grants the privilege of being able to observe the non-determinism of GC, and so should not be made accessible to code that shouldn't have such powers. It is the same reason why Maps and Sets, which are enumerable, enumerate their elements in a deterministic order.

In short, separation of concerns as well as separation of privileges.

If WeakMaps were granted the privilege of observing GC non-determinism via iteration, I assume it would be through a default WeakMap.prototype.@@iterator (that's how it works for Map). Removing this authority can be done by providing another WeakMap constructor with 'null' as WeakMap.prototype.@@iterator which is pretty much as much work as removing access to the weak-ref-maker.

Thanks to the iterator protocol (and especially the @@iterator symbol), privileges can be kept separate, so I don't think it's a sufficient enough reason to not allow iteration over WeakMaps if WeakRefs are in.

# Mark Miller (11 years ago)

On Tue, Mar 26, 2013 at 10:14 PM, David Bruant <bruant.d at gmail.com> wrote:

Le 26/03/2013 22:56, Mark S. Miller a ?crit :

Because the weak-map-maker constructor grants no privilege and can be generally accessible, whereas the weak-ref-maker grants the privilege of being able to observe the non-determinism of GC, and so should not be made accessible to code that shouldn't have such powers. It is the same reason why Maps and Sets, which are enumerable, enumerate their elements in a deterministic order.

In short, separation of concerns as well as separation of privileges.

If WeakMaps were granted the privilege of observing GC non-determinism via iteration, I assume it would be through a default WeakMap.prototype.@@iterator (that's how it works for Map). Removing this authority can be done by providing another WeakMap constructor with 'null' as WeakMap.prototype.@@iterator which is pretty much as much work as removing access to the weak-ref-maker.

Thanks to the iterator protocol (and especially the @@iterator symbol), privileges can be kept separate, so I don't think it's a sufficient enough reason to not allow iteration over WeakMaps if WeakRefs are in.

WeakRefs are not in ES6, because getting these privilege separation issues right is hard, and is best done after real experience using the new module system.

# Allen Wirfs-Brock (11 years ago)

On Mar 26, 2013, at 2:57 PM, David Bruant wrote:

Le 26/03/2013 21:12, Allen Wirfs-Brock a ?crit :

On Mar 26, 2013, at 12:18 PM, Mark S. Miller wrote:

WeakSet may or may not happen by ES6. But even if it doesn't, WeakSet is trivially shimmable on WeakMap.

Set is also shimmable on top of Map. If Set is in, there are as many reason to have WeakSets in. If WeakSets are considered as second class, so should Set. I feel Set and WeakSet fate should be bound.

It's really a consensus based judgement call based upon perceived breadth of utility. Both Map and WeakMap provide unique primitive functionality that is useful for creating other derived abstractions. Set can be implemented in terms of Map, but is expected to be used frequently enough that a consensus emerged for providing it as a built-in. WeakMap is used much less frequently than Map but is needed because of its primitive GC behavior. If WeakSet will have even a smaller frequency of use than WeakMap and is easily expressed using WeakMap, then maybe it doesn't carry its own weight. A few usage cases may not be enough. Convince us that it's wide utility justifies, the specification, implementation, and testing overhead it adds.

Which is why it isn't the in the spec. yet. It was introduced in support of Proxy private Symbol white list, but it is still unclear whether we will have them and even if we do, it's not clear that the actual internal whitelist needs to be exposed as a WeakSet.

I don't understand the reluctance towards having WeakSets in spec. They have as much use as WeakMaps. Domenic wrote a couple of messages ago "I have run into a few use cases for [WeakSet] (...), and was hoping it was on-track." I've had a case too and even left a comment about it [1]. We can argue whether, that's a use case more for private symbols than WeakSet, but still, weaksets sounds like an appriopriate tool for appropriate situations.

[1] DavidBruant/HarmonyProxyLab/blob/413a153c01b34bfc281b901b399ac09f3ca8c0d7/ES3AndProxy/ES5ObjectModelEmul.js#L57

I'm not sure why you didn't just define yourself a WeakSet shim based upon a WeakMap

# Kevin Gadd (11 years ago)

OK, it seems like Weak References are now being discussed without the context of previous discussions of weak references, which is a little annoying. Non-contrived real-world use cases that require Weak References (or a primitive with similar capabilities, like a Map with weak values instead of weak keys, I'm not picky) have already been provided on this list the last time WRs were discussed. I provided two based on real applications I've worked on; I thought other people in the discussion thread provided more.

What process needs to be followed before people will believe that Weak References are a real primitive that solves real problems? Do you need a set of broken, non-functional 'real world' applications written in JS that work in a customized version of V8/SpiderMonkey that has WRs? Do you need more verbose descriptions of use cases than previously provided? I can try to provide more justification than I did previously if this is necessary; I wasn't aware that it was.

I totally understand that security concerns and the limited number of hours in the day have caused WRs to be postponed until ES7 or later (though this makes me annoyed for obvious reasons), but if WRs as a useful feature are somehow in such question that people are suggesting they are unnecessary, I want to know how they got into this position and how to fix it.

The question of whether the non-determinism is justified is a hard one, of course. Right now applications that need WRs aren't JS applications, so WRs only pull their weight if it is worthwhile to have those applications brought into the browser (instead of remaining in native execution environments like NaCL or being emulated by a custom garbage collector implementation inside of emscripten with typed arrays acting as a virtual heap).

I can't answer the question of whether iterable WeakMaps are equivalent to weak references. I do believe that with iterable WeakMaps you could determine whether a given object has been collected, but I am having a hard time imagining how one could performantly implement a Weak Reference via an iterable WeakMap. The most obvious implementation would be to create a single-key WeakMap for every Weak Reference, and treating the reference as dead when the map contains 0 items. This would certainly 'work', but seems like a rather roundabout way of solving the problem. With an iterable WeakSet you'd at least be reducing the overhead, so that might be alright. If this roundabout solution could get into ES6, then I suppose I would probably prefer it to real WRs in ES<some larger digit>, because I prefer

solving customers' problems now to solving the problems of future customers later.

Thanks,

# Mark S. Miller (11 years ago)

On Tue, Mar 26, 2013 at 11:22 PM, Kevin Gadd <kevin.gadd at gmail.com> wrote:

OK, it seems like Weak References are now being discussed without the context of previous discussions of weak references, which is a little annoying. Non-contrived real-world use cases that require Weak References (or a primitive with similar capabilities, like a Map with weak values instead of weak keys, I'm not picky) have already been provided on this list the last time WRs were discussed. I provided two based on real applications I've worked on; I thought other people in the discussion thread provided more.

What process needs to be followed before people will believe that Weak References are a real primitive that solves real problems? Do you need a set of broken, non-functional 'real world' applications written in JS that work in a customized version of V8/SpiderMonkey that has WRs? Do you need more verbose descriptions of use cases than previously provided? I can try to provide more justification than I did previously if this is necessary; I wasn't aware that it was.

I totally understand that security concerns and the limited number of hours in the day have caused WRs to be postponed until ES7 or later (though this makes me annoyed for obvious reasons), but if WRs as a useful feature are somehow in such question that people are suggesting they are unnecessary, I want to know how they got into this position and how to fix it.

The question of whether the non-determinism is justified is a hard one, of course. Right now applications that need WRs aren't JS applications, so WRs only pull their weight if it is worthwhile to have those applications brought into the browser (instead of remaining in native execution environments like NaCL or being emulated by a custom garbage collector implementation inside of emscripten with typed arrays acting as a virtual heap).

I can't answer the question of whether iterable WeakMaps are equivalent to weak references. I do believe that with iterable WeakMaps you could determine whether a given object has been collected, but I am having a hard time imagining how one could performantly implement a Weak Reference via an iterable WeakMap. The most obvious implementation would be to create a single-key WeakMap for every Weak Reference, and treating the reference as dead when the map contains 0 items. This would certainly 'work', but seems like a rather roundabout way of solving the problem. With an iterable WeakSet you'd at least be reducing the overhead, so that might be alright. If this roundabout solution could get into ES6,

It can't, because it raises all the hard issues raised by weak-refs. We are not going to add issues this deep to ES6 at this date. We've already postponed easier issues to ES7.

# David Bruant (11 years ago)

Le 27/03/2013 00:22, Allen Wirfs-Brock a écrit :

On Mar 26, 2013, at 2:57 PM, David Bruant wrote:

Le 26/03/2013 21:12, Allen Wirfs-Brock a écrit :

On Mar 26, 2013, at 12:18 PM, Mark S. Miller wrote:

WeakSet may or may not happen by ES6. But even if it doesn't, WeakSet is trivially shimmable on WeakMap. Set is also shimmable on top of Map. If Set is in, there are as many reason to have WeakSets in. If WeakSets are considered as second class, so should Set. I feel Set and WeakSet fate should be bound.

It's really a consensus based judgement call based upon perceived breadth of utility. Both Map and WeakMap provide unique primitive functionality that is useful for creating other derived abstractions. Set can be implemented in terms of Map, but is expected to be used frequently enough that a consensus emerged for providing it as a built-in. WeakMap is used much less frequently than Map

Not in my experience, but maybe I tend to keep using objects as maps as a biased reflex. Regardless, the balance may weigh in favor of WeakMap if private symbols are given up.

but is needed because of its primitive GC behavior. If WeakSet will have even a smaller frequency of use than WeakMap and is easily expressed using WeakMap, then maybe it doesn't carry its own weight. A few usage cases may not be enough. Convince us that it's wide utility justifies, the specification, implementation, and testing overhead it adds.

Fair enough.

I'm not sure why you didn't just define yourself a WeakSet shim based upon a WeakMap

Laziness to be fully honest :-)

# David Bruant (11 years ago)

Le 26/03/2013 23:50, Mark Miller a écrit :

On Tue, Mar 26, 2013 at 10:14 PM, David Bruant <bruant.d at gmail.com <mailto:bruant.d at gmail.com>> wrote:

Le 26/03/2013 22:56, Mark S. Miller a écrit :

    Because the weak-map-maker constructor grants no privilege and
    can be generally accessible, whereas the weak-ref-maker grants
    the privilege of being able to observe the non-determinism of
    GC, and so should not be made accessible to code that
    shouldn't have such powers. It is the same reason why Maps and
    Sets, which are enumerable, enumerate their elements in a
    deterministic order.

    In short, separation of concerns as well as separation of
    privileges.

If WeakMaps were granted the privilege of observing GC
non-determinism via iteration, I assume it would be through a
default WeakMap.prototype.@@iterator (that's how it works for Map).
Removing this authority can be done by providing another WeakMap
constructor with 'null' as WeakMap.prototype.@@iterator which is
pretty much as much work as removing access to the weak-ref-maker.

Thanks to the iterator protocol (and especially the @@iterator
symbol), privileges can be kept separate, so I don't think it's a
sufficient enough reason to not allow iteration over WeakMaps if
WeakRefs are in.

WeakRefs are not in ES6, because getting these privilege separation issues right is hard, and is best done after real experience using the new module system.

I agree, but I don't see how it relates to what I wrote. What I tried to described was that assuming the existence of privilege separation mechanisms (which I admit is a hard problem, but I assume it solved in my argument), then mixed-trusted code can be provided either less built-ins (like removing access to the WeakRef constructor) or different built-ins (like a new WeakMap constructor which doesn't have the same .prototype.@@iterator)

I make the assumption of a privilege separation mechanisms/features/tools because either they exist (Caja), or are planned (proxies, module loader). Regardless of how many tweaks these will need, a privilege separation feature is something we need in a way or another, so no matter how hard it can be to build, it will be built.

Do you agree that assuming the existence of privilege separation features, removing access to WeakRef or WeakMap.prototype.@@iterator is an equivalent amount of work?

# Brendan Eich (11 years ago)

Please read the "memory safety and weak references" thread.

The issue is not just SES, which might remove an iterator in preparing the environment. Stock JS must not be vulnerable to jit-spray attacks due to enumerable weak maps.

# Jason Orendorff (11 years ago)

On Tue, Mar 26, 2013 at 3:05 PM, Brendan Eich <brendan at mozilla.com> wrote:

Hi Jason, agree on your request for non-contrived use-cases. I wrote about the general observer pub/sub problem here:

www.mail-archive.com/[email protected]/msg21480.html

Hope it helps.

Mmmmm. It does.

What would work here is determinism: gist.github.com/jorendorff/5245857

It seems to me you want some kind of deterministic finalization or scoped destructor. That's not in the cards for JS.

Oh -- no, my point was just that the API shown there can already be implemented just using 'finally'. I wasn't asking for any stronger guarantee than what 'finally' already provides.

# David Bruant (11 years ago)

Le 27/03/2013 15:52, Brendan Eich a écrit :

Please read the "memory safety and weak references" thread.

The issue is not just SES, which might remove an iterator in preparing the environment. Stock JS must not be vulnerable to jit-spray attacks due to enumerable weak maps. From what I understand of the attack, JS isn't vulnerable. Only current implementations are. I admit it carries some weight, but let's not confuse the 2.

# Brendan Eich (11 years ago)

David Bruant wrote:

Le 27/03/2013 15:52, Brendan Eich a écrit :

Please read the "memory safety and weak references" thread.

The issue is not just SES, which might remove an iterator in preparing the environment. Stock JS must not be vulnerable to jit-spray attacks due to enumerable weak maps. From what I understand of the attack, JS isn't vulnerable. Only current implementations are. I admit it carries some weight, but let's not confuse the 2.

No, you are misreading again. JS if it has enumerable weakmaps (you advocate) plus real-world vulns in its impls (which are inevitable) makes pwnage.

Changing the disagreement to be about JS vs. its impls is off the mark. Can you re-defend enumerability of weakmaps now that I've pointed out the security risk does not apply only to SES users, to be addressed by SES removing the @iterator?

# Sam Tobin-Hochstadt (11 years ago)

On Mar 27, 2013 6:40 PM, "Brendan Eich" <brendan at mozilla.com> wrote:

David Bruant wrote:

Le 27/03/2013 15:52, Brendan Eich a écrit :

Please read the "memory safety and weak references" thread.

The issue is not just SES, which might remove an iterator in preparing

the environment. Stock JS must not be vulnerable to jit-spray attacks due to enumerable weak maps.

From what I understand of the attack, JS isn't vulnerable. Only current

implementations are. I admit it carries some weight, but let's not confuse the 2.

No, you are misreading again. JS if it has enumerable weakmaps (you

advocate) plus real-world vulns in its impls (which are inevitable) makes pwnage.

Changing the disagreement to be about JS vs. its impls is off the mark.

Can you re-defend enumerability of weakmaps now that I've pointed out the security risk does not apply only to SES users, to be addressed by SES removing the @iterator?

I don't think this is quite the right equation. What Dion's attack shows is that conservative stack scanning, when combined with any ability to observe GC, will leak some information about the addresses of objects. This can almost certainly be generalized to any conservative scanning.

I also think that JS will inevitably need some method for GC-sensitive references, and this shows that combining these with conservative GC tech is risky. That may well be a reason to be more careful in the design of weak references, and to delay shipping them until engines improve. But I think the real lesson is that engines need to be on notice that conservative GC is a potential security risk, rather than a cost that the language has to bear forever. Fortunately, it seems that other incentives are already pushing engines toward precise GC.

# Brendan Eich (11 years ago)

Sam Tobin-Hochstadt wrote:

Changing the disagreement to be about JS vs. its impls is off the mark. Can you re-defend enumerability of weakmaps now that I've pointed out the security risk does not apply only to SES users, to be addressed by SES removing the @iterator?

I don't think this is quite the right equation.

I didn't mean to equate anything, but the issue in this thread that I was getting back to was observable lifetimes through weak map enumeration.

What Dion's attack shows is that conservative stack scanning, when combined with any ability to observe GC, will leak some information about the addresses of objects. This can almost certainly be generalized to any conservative scanning.

Agreed.

I also think that JS will inevitably need some method for GC-sensitive references, and this shows that combining these with conservative GC tech is risky. That may well be a reason to be more careful in the design of weak references, and to delay shipping them until engines improve. But I think the real lesson is that engines need to be on notice that conservative GC is a potential security risk, rather than a cost that the language has to bear forever. Fortunately, it seems that other incentives are already pushing engines toward precise GC.

It's true that conservative scanning is on the outs, sometimes as a matter of principle (David Ungar one remarked to me that he did not consider conservative GC to be real GC). But engines do it and ECMA-262 does not rule it out.

What makes conservative scanning troublesome, in the present case, is the design of weak maps as implemented in Tamarin (AS3 was the target Dion exploited).

My conclusion is different from yours, which I suggest is unfairly biased against conservative GC :-). I say we need careful weak ref notification (end-of-turn with an empty stack may be sufficient), and no enumeration of weakmaps. And that last conjunct is what David was disputing.

# Sam Tobin-Hochstadt (11 years ago)

On Wed, Mar 27, 2013 at 9:09 PM, Brendan Eich <brendan at mozilla.com> wrote:

What Dion's attack shows is that conservative stack scanning, when combined with any ability to observe GC, will leak some information about the addresses of objects. This can almost certainly be generalized to any conservative scanning.

Agreed.

I also think that JS will inevitably need some method for GC-sensitive references, and this shows that combining these with conservative GC tech is risky. That may well be a reason to be more careful in the design of weak references, and to delay shipping them until engines improve. But I think the real lesson is that engines need to be on notice that conservative GC is a potential security risk, rather than a cost that the language has to bear forever. Fortunately, it seems that other incentives are already pushing engines toward precise GC.

It's true that conservative scanning is on the outs, sometimes as a matter of principle (David Ungar one remarked to me that he did not consider conservative GC to be real GC). But engines do it and ECMA-262 does not rule it out.

I agree with all of that (including Ungar's opinion :). ECMA-262 doesn't rule out other security-risky implementation choices either [1].

What makes conservative scanning troublesome, in the present case, is the design of weak maps as implemented in Tamarin (AS3 was the target Dion exploited).

My conclusion is different from yours, which I suggest is unfairly biased against conservative GC :-). I say we need careful weak ref notification (end-of-turn with an empty stack may be sufficient), and no enumeration of weakmaps. And that last conjunct is what David was disputing.

I agree we need to be careful, and I don't think we should add weak map enumeration right now.

However, I think this demonstration makes a much stronger case against conservative GC. Dion's attack requires, fundamentally, three things:

  1. Conservative GC (of any form).
  2. Some data structure that the browser holds weakly if at all, but can be held strongly from JS.
  3. Some way to tell if that data is collected.

I think that there's no way to eliminate 2 & 3 from the browser. For example, 2 could be a large array, and 3 could be a currentMemoryUse function (which doesn't currently exist, but might).

Or, 2 could be image data (which browsers may discard when you scroll away, but not if JS has a reference to the DOM node in question) and 3 could be a site that detects HTTP re-requests for those images and communicates with the attacking script by XHR.

Or 2 could be any data structure that the browser memoizes creation of observably, and 3 is === on a new allocation of that structure.

Now, each of these particular issues could be mitigated. And probably some of them (like the image one) are way too slow to be practical for a full address leak. But, (a) just leaking some data helps defeat techniques like ASLR, (b) learning heap locations is bad, although perhaps not as bad as stack locations, and (c) browsers are a huge surface area to eliminate this behavior from.

This stuff is almost certainly not the low-hanging fruit that we'll see in the next Pwn2Own, but it's going to be next to impossible to eliminate entirely without precise collection.

Sam

[1] C++, for example.

# Brendan Eich (11 years ago)

Sam Tobin-Hochstadt wrote:

However, I think this demonstration makes a much stronger case against conservative GC. Dion's attack requires, fundamentally, three things:

  1. Conservative GC (of any form).
  2. Some data structure that the browser holds weakly if at all, but can be held strongly from JS.
  3. Some way to tell if that data is collected.

I think that there's no way to eliminate 2& 3 from the browser. For example, 2 could be a large array, and 3 could be a currentMemoryUse function (which doesn't currently exist, but might).

Such a currentMemoryUse function would not be easy to standardize, just on interop and complexity of implementation grounds, if not on the "liveness channel" attack.

But you are right in general: Dion tried a weakmap timing channel attack, since SpiderMonkey's WeakMap is based on doubling a HashMap when it fills to a certain load factor. However, he couldn't get that attack to work.

These channels may be noisy. The problem with weak refs with prompt notification, or enumerable weakmap, is that those leak much more precise liveness info.

Security is always like this, a set of cross-cutting (non-modular) properties -- safety properties in Fred Schneider's formulation (predicates over all future program states). So I don't see how we can look at conservative GC with an evil eye but not look at other parts of the system.

Let's say we ban conservative GC as part of ECMA-262's normative language. We still have interop and capability or "authority" problems with enumerable weakmaps. Those are not concerns only for SES.

I agree conservative GC makes the system more vulnerable, since (2) happens (even if under the hood, but in ES6 code "above the hood"), and (3) is an endless stream of weaknesses and hard-to-close channels.

# David Bruant (11 years ago)

Le 27/03/2013 00:22, Kevin Gadd a écrit :

OK, it seems like Weak References are now being discussed without the context of previous discussions of weak references, which is a little annoying. Non-contrived real-world use cases that require Weak References (or a primitive with similar capabilities, like a Map with weak values instead of weak keys, I'm not picky) have already been provided on this list the last time WRs were discussed. I provided two based on real applications I've worked on; I thought other people in the discussion thread provided more.

I've been through the thread and I haven't read any use case that requires Weak References. Only use cases where they make life easier to various degrees. It's been agreed that in most cases, adding an explicit .dispose() or equivalent protocol could work too. The only use case where I have some intuition of WeakRefs making a significant difference is the data binding use case. I find the "compile weakrefs from another language" use case a bit too early since compiling to JS is such a recent trend. As I said in one message, there is always a need of cutting some reference somewhere [1] for WeakRefs to work.

What process needs to be followed before people will believe that Weak References are a real primitive that solves real problems? Do you need a set of broken, non-functional 'real world' applications written in JS that work in a customized version of V8/SpiderMonkey that has WRs? Do you need more verbose descriptions of use cases than previously provided? I can try to provide more justification than I did previously if this is necessary; I wasn't aware that it was. From what I read, until Jason joined the discussion, it was mostly me that was being annoying on use cases. So I can give my criteria if that helps (as a reminder, I'm not part of TC39, so you're also free to ignore what I say). I'd like to see the description of a use case (something more specific than just "data binding") and an implementation that has been thought with memory management in mind. If this implementation proves to be minimalistic and simple enough, but yet too complex to use without WeakRefs, I'll be convinced. The "thought with memory management in mind" part is important. I don't think I have ever seen a talk describing a library where the author talked about the lifecycle of the objects created/used by the library. Memory footprint is sometimes discussed, but not lifecycle. From what I've observed, it's only after a severe memory leak is observed that people start to think about object lifecycle. Obviously, at that time, it's sometimes too late to do major refactoring and a lot of people would love to have weakrefs as a quickfix tool. From what I've observed too, very few people seem to understand GC at all. A lot of people still cite "cycles" as an issue of GC. So I wonder how many people really think of object lifecycles properly when designing libraries/frameworks.

But what if object lifecycle was considered in the design? Maybe we'd realize WeakRefs are necessary to dramatically reduce the burden/boilerplate of some use cases. Maybe we'd find out a different way of designing libraries and realize WeakRefs aren't that necessary after all.

Maybe tomorrow, i'll be writing a library and see the light or see the design of a library and see the light that without weakrefs, life is so much harder. I haven't yet come across such a case, so I'm not convinced yet.

David

[1] esdiscuss/2013-March/028935

# Sam Tobin-Hochstadt (11 years ago)

On Mon, Apr 1, 2013 at 8:34 AM, David Bruant <bruant.d at gmail.com> wrote:

Le 27/03/2013 00:22, Kevin Gadd a écrit :

OK, it seems like Weak References are now being discussed without the context of previous discussions of weak references, which is a little annoying. Non-contrived real-world use cases that require Weak References (or a primitive with similar capabilities, like a Map with weak values instead of weak keys, I'm not picky) have already been provided on this list the last time WRs were discussed. I provided two based on real applications I've worked on; I thought other people in the discussion thread provided more.

I've been through the thread and I haven't read any use case that requires Weak References. Only use cases where they make life easier to various degrees. It's been agreed that in most cases, adding an explicit .dispose() or equivalent protocol could work too.

Using .dispose() is manual management of the allocation and deallocation of object. Manual memory management is fundamentally non-modular -- you can't encapsulate it in a library, and it requires describing memory management behavior in all your function specifications, the way that C libraries do. It's certainly possible to write large, complex apps in C. But that's not evidence that we should bring those practices to JS.

# Brendan Eich (11 years ago)

Right.

David, I thought I had you convinced at:

www.mail-archive.com/[email protected]/msg21480.html

# Bill Frantz (11 years ago)

On 4/1/13 at 5:40 AM, samth at ccs.neu.edu (Sam Tobin-Hochstadt) wrote:

Using .dispose() is manual management of the allocation and deallocation of object. Manual memory management is fundamentally non-modular -- you can't encapsulate it in a library, and it requires describing memory management behavior in all your function specifications, the way that C libraries do. It's certainly possible to write large, complex apps in C. But that's not evidence that we should bring those practices to JS.

There are a bunch of different reasons for wanting to "dispose" an object in memory. With the malloc/free system from C, you usually dispose objects to recover their backing memory for future use. The C version is not memory safe.

If you are paying for the memory, you may be willing to break things to be able to stop paying. There may be some other reasons for causing an object to stop working and as a side effect recover most of its memory. A proxy can provide this service for JS, along with a number of other techniques all of which will be memory safe.

For short-lived programs, you can ignore memory disposal if the system running them will free the memory when they exit. This technique is memory safe and even works with mismanagement of references in a garbage collected systems. Having a system which supports just exiting and recovering memory is valuable for ad-hoc programming environments. It might also be valuable for ads running in long-lived web pages. Possibly some of the safe JS execution environments provide this service for the programs they mediate.

Memory safety is one really good reason to choose JS over C.

Cheers - Bill


Bill Frantz | "The only thing we have to | Periwinkle (408)356-8506 | fear is fear itself." - FDR | 16345 Englewood Ave www.pwpconsult.com | Inaugural address, 3/4/1933 | Los Gatos, CA 95032

# Kevin Gadd (11 years ago)

An important distinction here - and one I think Bill and Brendan and others have gotten at some, and I've been trying to get at - is that weak references (and similar concepts, like weak maps and weak event listeners) unfortunately encompass a set of different problems and end up being used to solve some (or all) of them in different contexts.

Resource management in the traditional 'memory and handles' sense is one of these contexts. History has, at this point, pretty much proven that you don't need a garbage collector to manage resources, but it has also pretty much proven that having one really helps. JS's garbage collector is a real win for ease of use (and safety, as Bill points out) in this area, but in practice JS rarely actually manipulates raw memory or handles to the extent that weak references are sorely needed. In cases where WRs are sorely needed, as well, the payoff is often significant enough to justify just going through and manually filling your code with calls to .dispose(). I've certainly done it dozens of times, and with enough discipline and process even big teams with junior programmers can manage it.

The context that motivates me to beg and plead for WRs, though, is a different one: Architecture and 'state management', so to speak, where the liveness of an object has real, semantic meaning beyond whether the memory that holds it has been freed and whether the object is reachable. The example I gave of an application with 'modes' is one of the best examples of this I've run into in my career, because it was a huge problem that kept tripping us up as we maintained and extended the application - being able to say at any point whether a mode needed to be alive, and whether its associated resources and event listeners needed to be alive, was a really big challenge. In some situations we solved this with explicit disposal, but in other situations we absolutely needed Weak References to keep things sane, and going through and manually breaking cycles and removing event listeners and nulling parent references simply would not have been scalable. Even our best programmers wouldn't have been able to do it consistently. A core part of the problem here is that the distinction between an 'important' reference - one that must keep an object alive - and an 'incidental' reference, that only need exist as long as it target does - is really hard (for me, at least) to convey through design/comments and enforce manually with code. Having the aid of the type system and the runtime here is a huge boon.

This is why the 'build your own malloc'/'build your own collector'/'do manual refcounting' solutions feel like a poor choice to me. Those solutions do a great job of solving resource management problems, because you can apply the cold unfeeling gaze of computer science to your software and eventually become confident that you will not have any resource management problems. The huge number of developers out there who intrinsically trust the garbage collector is great evidence of this. But when it comes to solving state/lifetime management problems, and being able to easily write code that you feel confident about in those contexts, solutions like manual refcounting or writing your own collector feel really inadequate. I've never come across a codebase that leaned upon solutions like that where you could feel true confidence; I've personally run into addref/release bugs in battle-tested codebases like Python and I've probably introduced my own more than a few times.

I hope this makes it clearer why I want WeakRefs in particular, and perhaps it makes it easier to understand what an alternative solution might look like. Maybe the alternative solution is sugar for doing light-weight scoped addref/release, like Python's 'with' statement, or some other simple mechanism where people can at least confidently build their own solutions with the aid of the runtime, I'm not really sure. There are certainly vast millions of lines of C++ out there more or less leaning on such constructs, and those apps seem to work!

# Marius Gundersen (11 years ago)

I've been through the thread and I haven't read any use case that requires Weak References. Only use cases where they make life easier to various degrees. It's been agreed that in most cases, adding an explicit .dispose() or equivalent protocol could work too.

Very few things added to ES6 is required, most of them makes the life of developers easier. Some of them only slightly improves our life (default variables, spreading, etc), while others change the way projects are structure (modules, classes, etc). WeakRefs would be such a feature. The use of WeakRefs instead of a .dispose() method is a major improvement in workflow, and allows some very interesting projects and data structures. As Kevin said:

"A core part of the problem here is that the distinction between an 'important' reference - one that must keep an object alive - and an 'incidental' reference, that only need exist as long as it target does"...

This is a concept which cannot be expressed in JavaScript today, but which most code actually needs to hint at in some way. Most objects are owned by one other object, and known by many other objects. The objects which knows of it shouldn't keep it alive, only the owner should. It is impossible to distinguish between these two cases in JavaScript today.

An example of this would be a GUI with event listening widgets, which is usually a tree where each widget is owned by its parent, and a widget without a parent should stop listening to events. There are many ways to implement this without WeakRefs, usually involving an explicit parent field and a dispose method when a widget is removed. But with WeakRefs this could be implemented so only the parent has a strong reference to the children, everyone else has weak references and so the widget (and all its children) are garbage collected and stop listening to events when the parent deletes it.

Hopefully this is enough of a usecase to make WeakRefs (or one of the alternatives, for example, an iterable set of weak references to functions/objects).

Marius Gundersen

# Mark S. Miller (11 years ago)

On Wed, Apr 3, 2013 at 2:13 AM, Marius Gundersen <gundersen at gmail.com>wrote:

I've been through the thread and I haven't read any use case that requires Weak References. Only use cases where they make life easier to various degrees. It's been agreed that in most cases, adding an explicit .dispose() or equivalent protocol could work too.

Very few things added to ES6 is required, most of them makes the life of developers easier.

Discussing whether weakrefs are required and for what is good. But please keep in mind that we're discussing ES7. It is way too late to add something like this to ES6.

# David Bruant (11 years ago)

Le 03/04/2013 11:13, Marius Gundersen a écrit :

"A core part of the problem here is that the distinction between an 'important' reference - one that must keep an object alive - and an 'incidental' reference, that only need exist as long as it target does"...

This is a concept which cannot be expressed in JavaScript today, but which most code actually needs to hint at in some way. Most objects are owned by one other object, and known by many other objects. The objects which knows of it shouldn't keep it alive, only the owner should. It is impossible to distinguish between these two cases in JavaScript today.

It is possible to make /a/ distinction with proxies. More specifically, with revocable proxies [1]

 let { proxy, revoke } = Proxy.revocable(target, handler);
 proxy.foo // traps
 revoke()
 proxy.foo // throws TypeError: "proxy is revoked"

Let's create a small abstraction on top of that:

 function RevocableRef(target){
     var transparentHandler = {};
     return Proxy.revocable(target, transparentHandler);
 }

You can keep the original target and the revoke function to yourself and decide only to share RevocableRefs of the object (which is pretty much the equivalent of wrapping with the WeakRef constructor). When you don't want others to access the object anymore, just call the revoke function.

It is one way to make a distinction between different references to the same object and keep control of who has access to which object at what time.

An example of this would be a GUI with event listening widgets, which is usually a tree where each widget is owned by its parent, and a widget without a parent should stop listening to events. There are many ways to implement this without WeakRefs, usually involving an explicit parent field and a dispose method when a widget is removed. But with WeakRefs this could be implemented so only the parent has a strong reference to the children, everyone else has weak references and so the widget (and all its children) are garbage collected and stop listening to events when the parent deletes it.

In that case, it seems that only the parent would keep a strong reference to a child widget and hand over a RevocableRef to other parties. When detaching the child widget, the parent would just need to call the revoke function. I admit this is more work than just detaching the child, but it is not a huge amount (calling one function). More interestingly, all the control of references remains at the parent level, that is, the parent decides which type of reference is shared (a revocable one or not); no need for third-parties to comply to a "dispose protocol", where different parties have to dispose, sometimes recursively which can be a mess.

The idea of being able to differentiate references is interesting, but doesn't seem to justify the non-determinism that comes with WeakRefs. It sounds that what we already have (revokable proxies and the RevocableRef abstraction above) would be enough in the use case you described (and Kevin's use case too from what I understand). If I misunderstood any of your (Kevin and Marius) use cases, could you explain what would be the added value of WeakRefs over revokable proxies.

Do languages which added WeakRefs have a form of revokable reference too? What difference would it make?

David

[1] strawman:revokable_proxies

# Mark S. Miller (11 years ago)

On Wed, Apr 3, 2013 at 11:20 AM, David Bruant <bruant.d at gmail.com> wrote:

Le 03/04/2013 11:13, Marius Gundersen a écrit :

"A core part of the problem here is that the distinction between an 'important' reference - one that must keep an object alive - and an 'incidental' reference, that only need exist as long as it target does"...

This is a concept which cannot be expressed in JavaScript today, but which most code actually needs to hint at in some way. Most objects are owned by one other object, and known by many other objects. The objects which knows of it shouldn't keep it alive, only the owner should. It is impossible to distinguish between these two cases in JavaScript today.

It is possible to make /a/ distinction with proxies. More specifically, with revocable proxies [1]

let { proxy, revoke } = Proxy.revocable(target, handler);
proxy.foo // traps
revoke()
proxy.foo // throws TypeError: "proxy is revoked"

Let's create a small abstraction on top of that:

function RevocableRef(target){
    var transparentHandler = {};
    return Proxy.revocable(target, transparentHandler);
}

You can keep the original target and the revoke function to yourself and decide only to share RevocableRefs of the object (which is pretty much the equivalent of wrapping with the WeakRef constructor). When you don't want others to access the object anymore, just call the revoke function.

It is one way to make a distinction between different references to the same object and keep control of who has access to which object at what time.

An example of this would be a GUI with event listening widgets, which is

usually a tree where each widget is owned by its parent, and a widget without a parent should stop listening to events. There are many ways to implement this without WeakRefs, usually involving an explicit parent field and a dispose method when a widget is removed. But with WeakRefs this could be implemented so only the parent has a strong reference to the children, everyone else has weak references and so the widget (and all its children) are garbage collected and stop listening to events when the parent deletes it.

In that case, it seems that only the parent would keep a strong reference to a child widget and hand over a RevocableRef to other parties. When detaching the child widget, the parent would just need to call the revoke function. I admit this is more work than just detaching the child, but it is not a huge amount (calling one function). More interestingly, all the control of references remains at the parent level, that is, the parent decides which type of reference is shared (a revocable one or not); no need for third-parties to comply to a "dispose protocol", where different parties have to dispose, sometimes recursively which can be a mess.

The idea of being able to differentiate references is interesting, but doesn't seem to justify the non-determinism that comes with WeakRefs. It sounds that what we already have (revokable proxies and the RevocableRef abstraction above) would be enough in the use case you described (and Kevin's use case too from what I understand). If I misunderstood any of your (Kevin and Marius) use cases, could you explain what would be the added value of WeakRefs over revokable proxies.

Do languages which added WeakRefs have a form of revokable reference too? What difference would it make?

E has both. In practice, my sense is that their use cases are disjoint, and that both are needed.

# David Bruant (11 years ago)

Le 03/04/2013 21:18, Mark S. Miller a ?crit :

Do languages which added WeakRefs have a form of revokable reference too? What difference would it make?

E has both. In practice, my sense is that their use cases are disjoint, and that both are needed.

Do you have examples of use? May be links to E code.

In what way is the GC-notification mechanism really necessary? (that's the part that I'm personally annoyed with most). I would be much less bothered if weakrefs were in essence revocable references for which only the GC has the revoke function (called on GC of the underlying target). It seems it would already solve the use cases exposed on the list which (my summary) Kevin expressed as "A core part of the problem here is that the distinction between an 'important' reference - one that must keep an object alive - and an 'incidental' reference, that only need exist as long as it target does"

Whatever final form is chosen (and even if weakrefs are only for ES7), would it make sense to unify what a revoked proxy and a dead weakref look like? Both look very close in what they are.

# Mark S. Miller (11 years ago)

On Wed, Apr 3, 2013 at 1:10 PM, David Bruant <bruant.d at gmail.com> wrote:

Le 03/04/2013 21:18, Mark S. Miller a écrit :

Do languages which added WeakRefs have a form of revokable reference

too? What difference would it make?

E has both. In practice, my sense is that their use cases are disjoint, and that both are needed.

Do you have examples of use? May be links to E code.

In what way is the GC-notification mechanism really necessary? (that's the part that I'm personally annoyed with most). I would be much less bothered if weakrefs were in essence revocable references for which only the GC has the revoke function (called on GC of the underlying target). It seems it would already solve the use cases exposed on the list which (my summary) Kevin expressed as "A core part of the problem here is that the distinction between an 'important' reference - one that must keep an object alive - and an 'incidental' reference, that only need exist as long as it target does"

Whatever final form is chosen (and even if weakrefs are only for ES7), would it make sense to unify what a revoked proxy and a dead weakref look like? Both look very close in what they are.

The main use of weakrefs in E is indeed related to proxies, but not in the way you may expect. Weakrefs are used to implement CapTP's distributed acyclic garbage collector. An E remote-reference-proxy is used as the local representative of a remote object. Though such E proxies are more like Q/ES7 promises than like ES6 proxies. A weakref is used to determine when there is no longer any local need for a reference to that remote object. When this is detected, the local vat sends a message (GCExportOp and GCAnswerOP at erights.org/elib/distrib/captp/DeliverOp.html#step9)

to the remote vat so the remote vat can clean up its corresponding incoming tables.

A captp-like protocol for distributed Q should make use of the same technique, but won't be able to until we add weakrefs to ES7. Until then, Q will leak a tremendous amount of distributed acyclic cross-vat garbage.