Closed duplode closed 10 years ago
Actually, the only reason why I'm using onChange
in this situation is to work around the fact that the browser will reset the caret whenever the value
property is set. I don't think the sinkWhen
is valuable for anything else, and I would prefer to not include it. (Widgets building on top of the input widget won't have to include the workaround.)
However, it's actually a nice function on the level of behaviors. I would call it
freezeB :: Behavior Bool -> Behavior a -> Behavior a
and it works by "freezing" at the last value of the second argument whenever the first argument becomes True. Here's a picture that hopefully conveys the idea:
Much to my surprise, it appears that this function cannot be implemented with the Reactive.Threepenny
API! (Not counting the internal functions like onChange
). That's very interesting.
P.S.: From reading the Reactive.Threepenny internals, I gather that making a pair in the way I just did is very cheap, as Behaviors synthesized with the Applicative instance are not cached. Is that correct?
Yes, but I wouldn't worry about that even if the answer were no. The FRP in implementation in Reactive.Threepenny
is just a prototype with no consideration to performance.
Implementing it on the level of behaviors would be certainly better, but as you say it isn't possible right now (my first attempt to avoid the onChange
issues was trying something along those lines). Maybe it is just FRP naïveté, but that didn't feel surprising to me - the problem seems to be that (i) freezeB
has to be defined in terms of the value of a Behavior
in a previous moment, and (ii) with the current API only an Event
can carry information about a specific moment.
P.S.: If I understood the issue well, dynamic event switching would make freezeB
possible. I really should try implementing it with reactive-banana as an exercise...
Using dynamic event switching, it is possible to implement at least a function
freezeEB :: Event Bool -> Behavior a -> Behavior a
Semantically, Behaviors are continuous and have no internal notion of "change event", but the funny thing is that the freezeB
still makes sense with these semantics. It boils down to the fact that for a discrete type like Bool
, there is a way to make sense of changes, along the lines of
flanks :: Behavior Bool -> Event Bool
In the long run, Threepenny will get dynamic event switching as well, of course. But other things may be more useful in the short term.
With the pull request withdrawn, I took the liberty of closing the issue. (There is the freezeB
idea, but I guess you'd rather track that separately, if at all.)
Inspired by your minimal widget example; more specifically, by how it disconnects view and model while the user edits. I believe the main selling point of
sinkWhen
is eliminating one reason for usingonChange
directly. The implementation combines boolean and value into a pair to ensure predictable results if both Behaviors change simultaneously (with separateonChange
handlers for each Behavior, if the boolean changed toFalse
at the same time that the value changed then whether the Attribute would be updated would depend on the execution order of the handlers).P.S.: From reading the Reactive.Threepenny internals, I gather that making a pair in the way I just did is very cheap, as Behaviors synthesized with the
Applicative
instance are not cached. Is that correct?