SodiumFRP / sodium

Sodium - Functional Reactive Programming (FRP) Library for multiple languages
http://sodium.nz/
Other
848 stars 138 forks source link

C# Cell Lift firing twice, but only propogating value from single execution #174

Closed etinquis closed 3 years ago

etinquis commented 3 years ago

I'm wondering whether the behavior I'm seeing with the following is as-expected:

[Test]
public void CellLift()
{
    int executions = 0;
    Cell<int> c1 = Cell.Constant(1);
    Cell<int> c2 = Cell.Constant(2);

    var result = c1.Lift(c2,
        (a, b) =>
        {
            return ++executions; // executed twice
        });
    result.Listen((i) => Console.WriteLine(i)); // executed once, with i == '1'
    Assert.AreEqual(result.Sample(), executions); // fails with sample() returning '1' and executions == '2'
}

When running this, I see the lift lambda runs twice and then the listen runs a single time with a value of 1. The sampled cell value contains 1 as well. I'd expect either the lift lambda only runs once (generating the 1 value), or the listen lambda runs twice (once for 1 and once for 2). In my use case, result is an expensively-constructed object that I'm trying to track via the cell, but I'm not getting all the generated result values.

jam40jeff commented 3 years ago

There is never a guarantee about when or how many times the lambda will run. The only guarantee you will get is that anything attached to the output of the Lift will only observe a single value in this case (as you are seeing). This shouldn't be a problem as all operators' lambdas should be (1) pure, (2) not throw exceptions, and (3) execute extremely quickly. Anything that doesn't match any of these 3 cases should be an "async" mapping by breaking out of the FRP network via a listener, running the process (optionally on a new thread if it is long-running), then pumping the result of that process back into a StreamSink (via a Post operation if a new thread was not created).

etinquis commented 3 years ago

Ok, I'll give that a shot. Thanks!