public static void DemonstrateVarAndExpression()
        {
            // A ReactiveVar is a simple mutable object with a Set method to update it in its entirety. It can turn
            // any existing type--often a primitive type--into a reactive type. You can create it with "new" or,
            // more concisely, with the factory method
            ReactiveVar <int> var1 = new ReactiveVar <int>(1);
            ReactiveVar <int> var2 = ReactiveVar(2);

            // A ReactiveExpression is computed based on other reactive data. When any of the components change, the expression itself changes
            Reactive <int> sumExpression = ReactiveExpression(() => var1.Value + var2.Value);

            // Expressions can depend on other expressions. They can call nested functions too, being arbitrarily complex
            Reactive <int> doubleSumExpression = ReactiveExpression(() => sumExpression.Value * 2);

            // React to changes in doubleSumExpression using the Changed event, showing a message when it changes.
            // Changed is used to run code with side effects when reactive data changes. It can, for instance, update UI.
            doubleSumExpression.Changed += () => {
                Console.WriteLine($"Double sum is now: {doubleSumExpression.Value}");
            };

            // All updates are made inside a transaction; if you try to update data outside a transaction, you'll get an error
            Transaction.Start();
            var1.Set(3);
            var2.Set(2);

            // Note that Changed notifications are only sent when the Transaction completes. That ensures all data is in it's final state and no "glitches" are possible.
            Console.WriteLine($"About to commit transaction; should show a new value of 10");
            Transaction.End();
        }
        public void TestIndexedListOnReactiveSequence()
        {
            var length = new ReactiveVar <int>(2);

            ParentSequence <int> rootSequence = Sequences(
                Items(0, 1, 2),
                Sequences(
                    Expression(() => CreateTestSequenceOfLength(length.Value)),
                    Items(3, 4, 5)
                    )
                );

            var list = new List <int>();

            new IndexedListOnSequence <int>(new ListInterfaceIndexedList <int>(list), rootSequence);

            AssertListRangeIs(list, start: 0, end: 3, firstValue: 0);
            AssertListRangeIs(list, start: 3, end: 5, firstValue: 100);
            AssertListRangeIs(list, start: 5, end: 8, firstValue: 3);
            Assert.AreEqual(8, list.Count);

            Transaction.Run(() => length.Set(3));
            AssertListRangeIs(list, start: 0, end: 3, firstValue: 0);
            AssertListRangeIs(list, start: 3, end: 6, firstValue: 100);
            AssertListRangeIs(list, start: 6, end: 9, firstValue: 3);
            Assert.AreEqual(9, list.Count);

            Transaction.Run(() => length.Set(0));
            AssertListRangeIs(list, start: 0, end: 3, firstValue: 0);
            AssertListRangeIs(list, start: 3, end: 6, firstValue: 3);
            Assert.AreEqual(6, list.Count);
        }
        public void TestNestedExpressions()
        {
            var term1 = new ReactiveVar <int>(1);
            var term2 = new ReactiveVar <int>(2);

            var           subexpression = new ReactiveExpression <int>(() => term1.Value + term2.Value);
            ChangedCalled subexpressionChangedCalled = EnsureChangedCalled(subexpression);

            var           term3                  = new ReactiveVar <int>(3);
            var           expression             = new ReactiveExpression <int>(() => subexpression.Value + term3.Value);
            ChangedCalled expressionChangeCalled = EnsureChangedCalled(expression);

            Transaction.Start();
            term3.Set(5);
            CompleteTransactionAndAssertChangedCalled(expressionChangeCalled);
            Assert.AreEqual(8, expression.Value);

            expressionChangeCalled.Reset();
            Transaction.Start();
            term1.Set(10);
            CompleteTransactionAndAssertChangedCalled(expressionChangeCalled);
            subexpressionChangedCalled.AssertCalled();

            Assert.AreEqual(17, expression.Value);
        }
        public void TestSet()
        {
            var           reactiveVar   = new ReactiveVar <int>(1);
            ChangedCalled changedCalled = EnsureChangedCalled(reactiveVar);

            Transaction.Start();
            reactiveVar.Set(2);
            changedCalled.AssertNotCalled();

            Transaction.End();
            changedCalled.AssertCalled();

            Assert.AreEqual(2, reactiveVar.Value);
        }
        public void TestSimpleExpression()
        {
            var term1 = new ReactiveVar <int>(1);
            var term2 = new ReactiveVar <int>(2);

            var expression = new ReactiveExpression <int>(() => term1.Value + term2.Value);

            Assert.AreEqual(3, expression.Value);

            ChangedCalled changedCalled = EnsureChangedCalled(expression);

            Transaction.Start();
            term1.Set(3);
            term2.Set(4);
            CompleteTransactionAndAssertChangedCalled(changedCalled);
            Assert.AreEqual(7, expression.Value);

            changedCalled = EnsureChangedCalled(expression);
            Transaction.Start();
            term1.Set(5);
            CompleteTransactionAndAssertChangedCalled(changedCalled);
            Assert.AreEqual(9, expression.Value);
        }