Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pruning old reactimate calls #198

Open
PaulJohnson opened this issue May 29, 2019 · 1 comment
Open

Pruning old reactimate calls #198

PaulJohnson opened this issue May 29, 2019 · 1 comment

Comments

@PaulJohnson
Copy link

I'm using Reactive Banana with gi-gtk to build a GUI application. I want to create a widget in response to an event and have that widget respond to changes in a Behavior and generate events for output. However I have a space-time leak from the interaction of reactimate with execute.

-- | Display the value in the behavior and emit events 
-- in response to user actions.
makeMyWidget :: Behavior DisplayValue -> MomentIO (Widget, Event Edit)

-- | Extract data specified by Foo into DisplayValue
getDisplay :: Foo -> AppState -> DisplayValue

triggerEvent :: Event Foo   -- The event that causes the widget to appear.

globalState :: Behavior AppState

-- | Add the argument to the GUI widget tree, dstroying any previous one.
showWidgetInGui :: Widget -> IO ()

So now I can write this:

runDisplays :: MomentIO (Event Edit)
   displays <- execute $ 
      makeMyWidget (\f -> getDisplay f <$> globalState) <$> triggerEvent
   reactimate $ showWidgetInGui . fst <$> displays
   switchE $ snd <$> displays

This seems to work fine. Every time the triggerEvent happens a new window pops up containing data extracted from globalState.

However when I trace the execution of getDisplay I see it being run for every past invocation as well as the one currently displayed. Presumably this is because the makeMyWidget includes reactimate' calls to update its display from the input behavior.

execute allows me to dynamically add processing to the event network, but I can't see any way of dynamically pruning old processing that is no longer needed.

I'm thinking of an API along the following lines:

-- | A reference to an existing "reactimate"
data Cookie

-- | The same as the existing function, but returning a cookie.
reactimate :: Event (IO ()) -> MomentIO (Cookie)

-- | Dynamically remove a reactimate from the network.
stopReactimate :: Cookie -> IO ()

With this I could put a bunch of reactimate calls inside an execute, collect all their cookies, and then have the corresponding stopReactimate calls as a callback from the destruction of the widget that they were updating. Having stopReactimate in the IO monad makes it easy to put in a callback like this. The data structures associated with the reactimate should also be cleared or dropped to allow the widget to be garbage collected along with everthing else.

@PaulJohnson
Copy link
Author

I've put in pull request #199 for an extension similar to what I described above.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant