Skip to content

Another problem with weak references and reactive-banana (different behavior in GHC vs GHCJS) #463

@ocharles

Description

@ocharles

cc @HeinrichApfelmus

The following program exhibits different behavior under GHC and GHCJS:

module Main (main) where

import Control.Concurrent
import Control.Monad
import Reactive.Banana
import Reactive.Banana.Frameworks

text_ :: Behavior String -> MomentIO (Behavior [()])
text_ contents =
  do contentsChanged <- changes contents
     reactimate' (fmap (fmap (const (print "X"))) contentsChanged)
     return (pure [()])

joinB :: Behavior (MomentIO (Behavior [()]))
      -> MomentIO (Behavior [()])
joinB b =
  do changed <- changes b
     initialB <- join (valueB b)
     laterB <- execute (b <@ changed)
     switchB initialB laterB

main :: IO ()
main =
  do n <-
       compile (do (tick,fireClick) <- newEvent
                   liftIOLater $
                     void $
                     forkIO $ forever $ threadDelay 1000000 >>= fireClick
                   reactimate (fmap print tick)
                   list <- accumB [] (fmap (:) tick)
                   nodes <-
                     joinB (fmap (fmap (fmap concat . sequenceA) .
                                  mapM (text_ . pure . show))
                                 list)
                   nodesChanged <- changes nodes
                   reactimate' (fmap (fmap (const (putStrLn "Changed"))) nodesChanged))
     actuate n
     forever (threadDelay maxBound)

In ghc:

()
Changed
()
Changed
()
Changed
()
Changed
()
Changed
()
Changed
()
Changed

In ghcjs:

()
Changed
()
Changed
()
Changed
<no more output>

In GHCJS it runs printing for 3 events and then stopping - suggesting a garbage collection has occured. In GHCI (and GHC compiled binaries) it counts without interruption (I aborted at 100, which takes 100 seconds).

I am running:

  • ghcjs-boot 97dea5c4145bf80a1e7cffeb1ecd4d0ecacd5a2f
  • ghcjs-shims 45f44f5f027ec03264b61b8049951e765cc0b23a
  • ghcjs 561365ba1667053b5dc5846e2a8edb33eaa3f6dd

@HeinrichApfelmus, I have also tried with the ghcjs branch of reactive-banana and the same problem occurs with that. I can also note that if I change the definition of text_ to just

text_ :: Behavior String -> MomentIO (Behavior [()])
text_ contents = return (pure [()])

the two programs behave identically. So it seems that by adding that extra reactimate', the dependency graph is different enough to exhibit different GC patterns. It is very strange to me that () doesn't even get printed, so we seem to be losing almost the entire graph. The click thread is still alive, if we add a print statement for every iteration of the forever loop, you'll see that, but nothing will actually happen otherwise.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions