Re: [Haskell-cafe] FRP memory leaks

2013-06-06 Thread Łukasz Dąbek
I was looking at reactive-banana and netwire (also Bacon.js).

Thank you for great explanation! Now I see that this kind of code must be
generating memory leak and solution using Bechavior was not clear for me
(as I am really new to the FRP stuff).

--
Łukasz Dąbek


2013/6/6 John Lato 

> Which FRP frameworks have you been looking at?
>
> In my experience, the most publicized leaks have been time leaks, which
> are a particular type of memory leak related to switching.  However, the
> presence of time leaks mostly arises in terms of the FRP implementation.
>  Arrowized FRP (e.g. Yampa, netwire) do not typically suffer from this for
> example.  Some libraries that implement the semantics of Conal Elliott's
> "Push-pull functional reactive programming" (or similar semantics) have
> been susceptible to this, however recent implementations are not.  Sodium,
> elerea, and reactive-banana for example have generally overcome the worst
> issues present in earlier systems.  Leaks can still be present in current
> systems of course, but now they're generally due to the programmer
> unintentionally retaining data in a case that's much simpler to reason
> about.  That is, the situation today is more similar to forgetting to use
> deepseq or similar, rather than the prior leaks that were very difficult to
> reason about.
>
> I think the most common current issue is that a very natural way of
> accumulating reactive events across time can leak.  Suppose you have a
> library of reactive widgets, where each widget has an associated stream of
> IO actions that you want to run.  E.g. clicking a button prints it, sliding
> a scale prints the value, etc.
>
> > class Actionable a where
> >   actions :: a -> Event (IO ())
>
> suppose you have a collection that allows you to add/remove Actionable
> things to it (e.g. a button panel).  This panel has an action stream that's
> simply the concatenation of those of its components.  One possible
> implementation looks like this:
>
> > data ButtonPanel = ButtonPanel (Event (IO ())
>
> > emptyPanel = ButtonPanel mempty
>
> > addActionable :: Actionable a => ButtonPanel -> a -> ButtonPanel
> > addActionable (ButtonPanel e) a = ButtonPanel (e <> actions a)
>
> I've omitted all the parts for wiring up the gui, but suppose they're
> handled also, and removing a button from the panel just removes it from the
> gui and destroys the widget.  After that, the button's event stream is
> empty, so you can just leave the ButtonPanel's event stream unchanged,
> because the destroyed button will never fire.
>
> This is a memory leak.  The destroyed Button's event stream is still
> referenced in the ButtonPanel event stream, so data related to it never
> gets freed.  Over time your FRP network will grow, and eventually you'll
> hit scaling problems.
>
> The proper solution in this instance is to keep a list of each button's
> event stream within the button panel.  It's ok to keep a cached aggregate
> stream, but that cache needs to be re-built when a button is removed.  This
> is usually fairly natural to do with FRP, but your ButtonPanel may look
> like this instead:
>
> > data ButtonPanel = ButtonPanel  (Map Key (Event (IO ()))
>
> > addActionable :: Actionable a => ButtonPanel-> Key -> a -> ButtonPanel
> > removeActionable :: ButtonPanel -> Key -> ButtonPanel
>
> and now you need to manage some sort of Key for collection elements.
>
> This style isn't entirely idiomatic FRP.  Instead of these functions, you
> could have all your modifications handled via the FRP framework.  For
> example,
>
> > data ButtonPanel = ButtonPanel (Behavior (Map Key (Event (IO ()
> > buttonPanel :: Actionable a => Event (Key,a) -> Event Key -> ButtonPanel
>
> but you still need to be aware that objects can reference older objects.
>  Behaviors are frequently created via accumulators over events (e.g.
> accumB), and if the accumulation is doing something like 'mappend', a
> memory leak is likely.
>
> Basically, the issue is that when you're accumulating reactive stuff over
> time, you need to be sure that your accumulator doesn't reference data that
> is otherwise expired.  This example uses a push-pull style pseudocode
> because that's what I'm most familiar with.  I'm not entirely show how (or
> if) this translates to arrowized FRP, although it wouldn't surprise me if
> there's a similar pattern.
>
>
> On Thu, Jun 6, 2013 at 2:50 AM, Łukasz Dąbek  wrote:
>
>> Hello, Cafe!
>>
>> I've heard that one of the problems of FRP (Functional Reactive
>> Programming) is that it's easy to create memory leaks. However I cannot
>> find any natural examples of such leaks. Could anybody post some
>> (pseudo)code demonstrating this phenomenon? Preferably something that
>> arises when one is writing bigger applications in FRP style.
>>
>> Thanks in advance!
>>
>> --
>> Łukasz Dąbek
>>
>> ___
>> Haskell-Cafe mailing list
>> Haskell-Cafe@haskell.org
>> http://www.haskell.org/mailman/listinf

Re: [Haskell-cafe] FRP memory leaks

2013-06-05 Thread John Lato
Which FRP frameworks have you been looking at?

In my experience, the most publicized leaks have been time leaks, which are
a particular type of memory leak related to switching.  However, the
presence of time leaks mostly arises in terms of the FRP implementation.
 Arrowized FRP (e.g. Yampa, netwire) do not typically suffer from this for
example.  Some libraries that implement the semantics of Conal Elliott's
"Push-pull functional reactive programming" (or similar semantics) have
been susceptible to this, however recent implementations are not.  Sodium,
elerea, and reactive-banana for example have generally overcome the worst
issues present in earlier systems.  Leaks can still be present in current
systems of course, but now they're generally due to the programmer
unintentionally retaining data in a case that's much simpler to reason
about.  That is, the situation today is more similar to forgetting to use
deepseq or similar, rather than the prior leaks that were very difficult to
reason about.

I think the most common current issue is that a very natural way of
accumulating reactive events across time can leak.  Suppose you have a
library of reactive widgets, where each widget has an associated stream of
IO actions that you want to run.  E.g. clicking a button prints it, sliding
a scale prints the value, etc.

> class Actionable a where
>   actions :: a -> Event (IO ())

suppose you have a collection that allows you to add/remove Actionable
things to it (e.g. a button panel).  This panel has an action stream that's
simply the concatenation of those of its components.  One possible
implementation looks like this:

> data ButtonPanel = ButtonPanel (Event (IO ())

> emptyPanel = ButtonPanel mempty

> addActionable :: Actionable a => ButtonPanel -> a -> ButtonPanel
> addActionable (ButtonPanel e) a = ButtonPanel (e <> actions a)

I've omitted all the parts for wiring up the gui, but suppose they're
handled also, and removing a button from the panel just removes it from the
gui and destroys the widget.  After that, the button's event stream is
empty, so you can just leave the ButtonPanel's event stream unchanged,
because the destroyed button will never fire.

This is a memory leak.  The destroyed Button's event stream is still
referenced in the ButtonPanel event stream, so data related to it never
gets freed.  Over time your FRP network will grow, and eventually you'll
hit scaling problems.

The proper solution in this instance is to keep a list of each button's
event stream within the button panel.  It's ok to keep a cached aggregate
stream, but that cache needs to be re-built when a button is removed.  This
is usually fairly natural to do with FRP, but your ButtonPanel may look
like this instead:

> data ButtonPanel = ButtonPanel  (Map Key (Event (IO ()))

> addActionable :: Actionable a => ButtonPanel-> Key -> a -> ButtonPanel
> removeActionable :: ButtonPanel -> Key -> ButtonPanel

and now you need to manage some sort of Key for collection elements.

This style isn't entirely idiomatic FRP.  Instead of these functions, you
could have all your modifications handled via the FRP framework.  For
example,

> data ButtonPanel = ButtonPanel (Behavior (Map Key (Event (IO ()
> buttonPanel :: Actionable a => Event (Key,a) -> Event Key -> ButtonPanel

but you still need to be aware that objects can reference older objects.
 Behaviors are frequently created via accumulators over events (e.g.
accumB), and if the accumulation is doing something like 'mappend', a
memory leak is likely.

Basically, the issue is that when you're accumulating reactive stuff over
time, you need to be sure that your accumulator doesn't reference data that
is otherwise expired.  This example uses a push-pull style pseudocode
because that's what I'm most familiar with.  I'm not entirely show how (or
if) this translates to arrowized FRP, although it wouldn't surprise me if
there's a similar pattern.


On Thu, Jun 6, 2013 at 2:50 AM, Łukasz Dąbek  wrote:

> Hello, Cafe!
>
> I've heard that one of the problems of FRP (Functional Reactive
> Programming) is that it's easy to create memory leaks. However I cannot
> find any natural examples of such leaks. Could anybody post some
> (pseudo)code demonstrating this phenomenon? Preferably something that
> arises when one is writing bigger applications in FRP style.
>
> Thanks in advance!
>
> --
> Łukasz Dąbek
>
> ___
> Haskell-Cafe mailing list
> Haskell-Cafe@haskell.org
> http://www.haskell.org/mailman/listinfo/haskell-cafe
>
>
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe