threepenny-gui: garbage collection

Suppose that each time I make a particular threepenny-gui widget, call it a `Foo`, I register an event handler using `on` so that the `Foo` can change its appearance based on some `Event`. Suppose I create, show, and hide a billion `Foo`s, each one never to be shown again. Can they be garbage collected? Presumably there is something storing the callback that was registered for the `Event` and the callback refers to the `Foo`. How then can the `Foo`s be freed? `Reactive.Threepenny.register` talks about an "unregister" action but says "FIXME: Unregistering event handlers does not work yet.". But how could it be known anyway when to unregister? Is there not the possibility of a space leak regardless? Thanks, Tom

Tom Ellis wrote:
Suppose that each time I make a particular threepenny-gui widget, call it a `Foo`, I register an event handler using `on` so that the `Foo` can change its appearance based on some `Event`.
Suppose I create, show, and hide a billion `Foo`s, each one never to be shown again. Can they be garbage collected? Presumably there is something storing the callback that was registered for the `Event` and the callback refers to the `Foo`. How then can the `Foo`s be freed?
`Reactive.Threepenny.register` talks about an "unregister" action but says "FIXME: Unregistering event handlers does not work yet.". But how could it be known anyway when to unregister? Is there not the possibility of a space leak regardless?
(Threepenny author here.) This is a classic example of a circular reference that occurs in every GUI program: A widget keeps a reference to an event handler, which in turn keeps a reference to the widget. Of course, GHC's has a well-designed garbage collector that can handle this, but in Threepenny, the situation is actually worse: the widget is managed by the JavaScript runtime, whereas the event handler is managed by the Haskell runtime. I don't know any garbage collector that can resolve cross-runtime circular dependencies. Still, I managed to solve this problem to some extend. :) Essentially, Threepenny mirrors dependencies between JavaScript DOM elements on the Haskell side, and thus allows the Haskell garbage collector to handle this. (I wouldn't want to touch JavaScript garbage collectors with a ten-foot pole.) For your concrete situation, this means that as long as the `Foo` widgets are not inserted into the DOM tree in the browser, and you only use DOM events on them (`UI.click` etc), they will indeed be garbage collected properly whenever their lifetime ends in your Haskell program. (At least, that's the plan. I have tested that it works, but garbage collection is a tricky business, so I wouldn't bet my life on it just yet.) Note that I do have to mirror the JavaScript memory layout, so this only works for the `Element` type at the moment. If you use the `ffiExport` function to export event handlers to the JavaScript side, then they will not be garbage collected. The `Reactive.Threepenny.register` function is totally separate from this, because it doesn't talk to the JavaScript runtime at all. You're right that there might be some issues with `unregister`, but I haven't thought about this yet. Best regards, Heinrich Apfelmus -- http://apfelmus.nfshost.com

On Sat, Jan 03, 2015 at 11:34:07AM +0100, Heinrich Apfelmus wrote:
Tom Ellis wrote:
Suppose that each time I make a particular threepenny-gui widget, call it a `Foo`, I register an event handler using `on` so that the `Foo` can change its appearance based on some `Event`.
Suppose I create, show, and hide a billion `Foo`s, each one never to be shown again. Can they be garbage collected? Presumably there is something storing the callback that was registered for the `Event` and the callback refers to the `Foo`. How then can the `Foo`s be freed?
`Reactive.Threepenny.register` talks about an "unregister" action but says "FIXME: Unregistering event handlers does not work yet.". But how could it be known anyway when to unregister? Is there not the possibility of a space leak regardless?
(Threepenny author here.)
This is a classic example of a circular reference that occurs in every GUI program: A widget keeps a reference to an event handler, which in turn keeps a reference to the widget.
Hi Heinrich, thanks for your reply. Actually I don't think I am thinking of a circular reference problem. The problem I am evisaging is that the `Event` keeps a reference to the event handler which in turn keeps a reference to the widget. Thus it is hard to see how the widget can be freed before the `Event`. A quick Google shows this indeed a common problem in GUI programming, e.g. http://stackoverflow.com/questions/4526829/why-and-how-to-avoid-event-handle... Is my understanding correct, or is my model of how `Event`s work in threepenny-gui wrong?
Of course, GHC's has a well-designed garbage collector that can handle this, but in Threepenny, the situation is actually worse: the widget is managed by the JavaScript runtime, whereas the event handler is managed by the Haskell runtime. I don't know any garbage collector that can resolve cross-runtime circular dependencies.
I haven't managed to understand the issue here. Could you say a bit more about that? It sounds interesting! I don't think it's related to my concern though, but if it is that would also be interesting. Tom

Tom Ellis wrote:
Heinrich Apfelmus wrote:
Tom Ellis wrote:
Suppose that each time I make a particular threepenny-gui widget, call it a `Foo`, I register an event handler using `on` so that the `Foo` can change its appearance based on some `Event`.
Suppose I create, show, and hide a billion `Foo`s, each one never to be shown again. Can they be garbage collected? Presumably there is something storing the callback that was registered for the `Event` and the callback refers to the `Foo`. How then can the `Foo`s be freed?
[..]
This is a classic example of a circular reference that occurs in every GUI program: A widget keeps a reference to an event handler, which in turn keeps a reference to the widget.
Hi Heinrich, thanks for your reply.
Actually I don't think I am thinking of a circular reference problem. The problem I am envisaging is that the `Event` keeps a reference to the event handler which in turn keeps a reference to the widget. Thus it is hard to see how the widget can be freed before the `Event`. A quick Google shows this indeed a common problem in GUI programming, e.g.
http://stackoverflow.com/questions/4526829/why-and-how-to-avoid-event-handle...
Consider this: Who keeps a reference to the `Event`? (If no one keeps a reference to the `Event`, then it can be garbage collected, and so can the event handler and the widget.)
Is my understanding correct, or is my model of how `Event`s work in threepenny-gui wrong?
Of course, GHC's has a well-designed garbage collector that can handle this, but in Threepenny, the situation is actually worse: the widget is managed by the JavaScript runtime, whereas the event handler is managed by the Haskell runtime. I don't know any garbage collector that can resolve cross-runtime circular dependencies.
I haven't managed to understand the issue here. Could you say a bit more about that? It sounds interesting! I don't think it's related to my concern though, but if it is that would also be interesting.
The issue is still that there is a circular dependency widget -> Event -> event handler -> widget Now, this wouldn't be a problem if all these references were managed by GHC. Our beloved Haskell compiler can handle circular references just fine, they will be garbage collected at once whenever there is no more "outside" reference to the whole cycle. The real issue, which is specific to Threepenny, is that not all references are managed by GHC. Instead, some are managed by the JavaScript engine in the browser. In other words, the circular dependency crosses language boundaries -- and now it becomes hard to garbage collect it. Best regards, Heinrich Apfelmus -- http://apfelmus.nfshost.com

On Mon, Jan 05, 2015 at 06:31:57PM +0100, Heinrich Apfelmus wrote:
Tom Ellis wrote:
Heinrich Apfelmus wrote:
Tom Ellis wrote:
Suppose that each time I make a particular threepenny-gui widget, call it a `Foo`, I register an event handler using `on` so that the `Foo` can change its appearance based on some `Event`.
Suppose I create, show, and hide a billion `Foo`s, each one never to be shown again. Can they be garbage collected? Presumably there is something storing the callback that was registered for the `Event` and the callback refers to the `Foo`. How then can the `Foo`s be freed?
[..]
This is a classic example of a circular reference that occurs in every GUI program: A widget keeps a reference to an event handler, which in turn keeps a reference to the widget.
Hi Heinrich, thanks for your reply.
Actually I don't think I am thinking of a circular reference problem. The problem I am envisaging is that the `Event` keeps a reference to the event handler which in turn keeps a reference to the widget. Thus it is hard to see how the widget can be freed before the `Event`. A quick Google shows this indeed a common problem in GUI programming, e.g.
http://stackoverflow.com/questions/4526829/why-and-how-to-avoid-event-handle...
Consider this: Who keeps a reference to the `Event`?
(If no one keeps a reference to the `Event`, then it can be garbage collected, and so can the event handler and the widget.)
I am suggesting that the `Event` originates elsewhere, perhaps from some other widget that we wish to have a long life, but we want to attach short-lived widgets to it via event handlers. Can we do that without having to explicitly unregister the handlers when we want the short-lived widgets to be garbage collected? Tom

Tom Ellis wrote:
On Mon, Jan 05, 2015 at 06:31:57PM +0100, Heinrich Apfelmus wrote:
Tom Ellis wrote:
Heinrich Apfelmus wrote:
Tom Ellis wrote:
Suppose that each time I make a particular threepenny-gui widget, call it a `Foo`, I register an event handler using `on` so that the `Foo` can change its appearance based on some `Event`.
Suppose I create, show, and hide a billion `Foo`s, each one never to be shown again. Can they be garbage collected? Presumably there is something storing the callback that was registered for the `Event` and the callback refers to the `Foo`. How then can the `Foo`s be freed?
[..] This is a classic example of a circular reference that occurs in every GUI program: A widget keeps a reference to an event handler, which in turn keeps a reference to the widget. Hi Heinrich, thanks for your reply.
Actually I don't think I am thinking of a circular reference problem. The problem I am envisaging is that the `Event` keeps a reference to the event handler which in turn keeps a reference to the widget. Thus it is hard to see how the widget can be freed before the `Event`. A quick Google shows this indeed a common problem in GUI programming, e.g.
http://stackoverflow.com/questions/4526829/why-and-how-to-avoid-event-handle... Consider this: Who keeps a reference to the `Event`?
(If no one keeps a reference to the `Event`, then it can be garbage collected, and so can the event handler and the widget.)
I am suggesting that the `Event` originates elsewhere, perhaps from some other widget that we wish to have a long life, but we want to attach short-lived widgets to it via event handlers. Can we do that without having to explicitly unregister the handlers when we want the short-lived widgets to be garbage collected?
Well, of course then you have to unregister the event handlers, otherwise they will reference the widget. If you don't unregister them, then they will, in fact, be long-lived by definition, because the widget could still react to the event. Best regards, Heinrich Apfelmus -- http://apfelmus.nfshost.com
participants (2)
-
Heinrich Apfelmus
-
Tom Ellis