reflex-vty icon indicating copy to clipboard operation
reflex-vty copied to clipboard

And undocumented causality loop in layout computation

Open deepfire opened this issue 1 year ago • 5 comments

The following is not a causality loop:

      displayHeight >>= sample . current             

..but this one is:

      tile (fixed 1) $ displayHeight >>= sample . current

I guess this can be somewhat surprising to the user, since the semantics are not exactly explained in the documentation.

deepfire avatar Sep 23 '24 17:09 deepfire

As a general rule, one should usually avoid sample in any widget code (not only here, but in reflex-dom as well), because it's strict in a way which interacts poorly with the way we use recursion to order widgets visually. It can be quite frustrating, because things will often work fine until you go and use your widget inside a larger application and suddenly get a mysterious causality loop at runtime coming from a sample that's a few layers down.

It's kind of an accident of the way they get constructed that the widget monads have MonadSample instances, and it's possible we ought to find a way to simply disable those in ordinary widget code. (The correct and safe place to use sample is typically inside the corresponding push/pull monads.)

cgibbard avatar Sep 23 '24 17:09 cgibbard

It can be quite frustrating, because things will often work fine until you go and use your widget inside a larger application and suddenly get a mysterious causality loop at runtime coming from a sample that's a few layers down.

That is exactly my experience -- thank you for the relief of not being alone in the suffering! : -)

deepfire avatar Sep 23 '24 18:09 deepfire

If you have a Dynamic and want to use its value from the widget code, usually you want to first make sure that the Dynamic is passed down as far as reasonable to the widget that it ought to have an impact on, and then possibly use dyn to switch widgets, if the whole structure of the widget is meant to change based on the value, or, more ideally, you just process it into other Dynamics and such (e.g. using fmap) that plug directly into the primitive widgets, for example, if some text or colours are meant to change based on it.

cgibbard avatar Sep 23 '24 18:09 cgibbard

@cgibbard, by the way, I have hoogled for dyn, yet alas to no avail:

hoogle --count=1000 dyn | grep -w dyn
Language.Haskell.TH.Lib dyn :: Quote m => String -> m Exp
Language.Haskell.TH.Lib.Internal dyn :: Quote m => String -> m Exp

deepfire avatar Sep 23 '24 19:09 deepfire

Apologies, I was thinking of https://hackage.haskell.org/package/reflex-dom-core-0.8.1.0/docs/Reflex-Dom-Widget-Basic.html#v:dyn

which for some reason is exposed in Reflex as networkView (this whole module is weirdly named, these functions have nothing to do with networks): https://hackage.haskell.org/package/reflex-0.9.3.0/docs/Reflex-Network.html

cgibbard avatar Sep 23 '24 19:09 cgibbard