A funny thing happened to me when I was presenting Bacon.js at the great Oredev conference a few weeks ago. You could say my own dogs bit me. What happened was that I used
map
to get the current value of a text field to be associated with a Bacon event.
The thing is, methods such as
map
and the combine
use lazy evaluation to avoid evaluating values that aren't actually needed. This can be generally considered a Good Thing, but it has it's pitfalls.
If you pass a function that referentially transparent, you'll be fine. This means that your function should return the same value regardless of when it's called.
On the other hand, if you pass a function that returns a value depending on time, you may have problems. Consider a property
contents
that's derived from events like below.var items = clicks.map(getCurrentValueFromUI).toProperty()
var submittedItems = items.sampledBy(submitClick)
Now the
submittedItems
stream will produce the current value of the items
property when an event occurs in the submitClick
stream. Or so you'd think. In fact, the value of submittedItems
is evaluated at the time of the event in the submitClick
stream, which means that it will actually produce the value of getCurrentValueFromUI
at that time, instead of at the time of the originalclick
event.
To force evaluation at the time of original event, you can just use
flatMap
instead of map
. As in here.
var items = clicks.flatMap(getCurrentValueFromUI).toProperty()
So there I was, on the stage, looking stupid because of lazy evaluation.
Now, looking stupid in places is what I do every day but, if it lazy evaluation fools me (the guy who wrote it), maybe it's not reasonable to expect new Bacon.js users to do well with lazy eval.
So, I opened an issue on Github where I kinda suggest that we should remove lazy evaluation in Bacon.js 0.8. What do you think?
Oh, and should I go to Minsk to the Rolling Scopes conference next year?
No comments:
Post a Comment