What is the Evaluation Model of Bacon.js?

342 Views Asked by At

Most resources on reactive programming, e.g. "A Survey on Reactive Programming" (Bainomugisha et al., 2012), introduce several characteristics by which different reactive solutions can be classified. One of these is which evaluation model is employed, that is, whether the reactive language (or library) is push-based or pull-based (or both).

Example: Let's take a look a this piece of pseudocode: var c = a + b; In a reactive environment, c is expected to always contain the sum of a and b. Accordingly, if a or b change, the value of c has to be recomputed. In a push-based solution, a and b notify c when their values have changed, so that c's value can be recomputed instantly. In a pull-based solution, c looks up the current values of a and b as soon as the value c itself is being demanded. Thus, all recomputations are being delayed until c's value is requested.

For quite some time now, I have tried to figure out what evaluation model is being employed by the JavaScript library Bacon.js. Let's assume the following:

var a = Bacon.constant(21); // Creates a Property
var b = Bacon.constant(21);
var c = a.combine(b, function (x, y) {
    return x + y;
});

According to this section of the Bacon.js documentation, combinators such as combine use lazy evaluation, that is, they "avoid evaluating values that aren't actually needed".

  • Question 1: When are values "actually" needed?
  • Question 2: Is it safe to assume that--at least in the case of the example above--Bacon.js employs a pull-based approach? Or am I mixing things up here?

However, towards the end of the section, the Bacon.js documentation mentions that if one wants "[t]o force evaluation at the time of original event, [one] can just use flatMap". Really, now I am confused:

  • Question 3: Respectively, is it safe to assume that Bacon.js employs a push-based evaluation model whenever I use flatMap? Or am I mixing things up here--again?
  • Question 4: I cannot really reproduce the example from above using flatMap instead of combine. Does that mean that depending on what I am trying to do, Bacon.js sometimes employs a pull-based propagation of change, and sometimes it comes up with a push-based one?

To the one who can provide clarification, I would be very greatful. :P

1

There are 1 best solutions below

2
On
  1. Value is "needed" when a Subscriber calls the value() method of an event. This happens in all .on Value subscribers for instance. Combinators like map and combine do not evaluate the input values until their respective value is required. On the other hand, flatMap(f) needs to evaluate, because it uses the value to spawn a new stream using the provided function f. Also scan is currently eager.

  2. As described above, it's a mixture of push and pull in the sense that evaluation occurs when necessary. In fact, Bacon.js is not based on any research papers and does not comply with any theoretical models.

  3. No, don't assume any models. Instead, use referentially transparent functions and let the system decide when it needs to evaluate them.

  4. Surely you cannot reproduce the same functionality with flatMap that you can with combine.