uCalc API Version: 2.1.3-preview.2 Released: 6/16/2026
Warning
uCalc API Preview Release Notice:The documentation describes the intended behavior of the API. The current preview build contains incomplete features, unoptimized performance, and is subject to breaking changes.
Project: Creating a Spreadsheet Formula Evaluator
Product:
Class:
A step-by-step project to build a reactive spreadsheet engine where changing one cell automatically updates all dependent cells.
Remarks
📊 Project: Creating a Spreadsheet Formula Evaluator
This project demonstrates one of uCalc's most powerful features: building a reactive calculation engine, similar to a spreadsheet. You'll learn how to define cells with formulas that depend on other cells and see how uCalc automatically handles the complex task of recalculating dependencies when a value changes.
The Goal: A Reactive Spreadsheet
Our goal is to simulate a simple spreadsheet where:
- Cell
A1contains the value10. - Cell
B1contains the formulaA1 * 2. - Cell
C1contains the formulaA1 + B1.
The critical requirement is that if we change the value of A1, the values of B1 and C1 must update automatically, without any manual intervention.
The Challenge: Dependency Tracking
In a traditional programming environment, solving this problem is surprisingly complex. You would need to:
- Parse Formulas: Manually parse each formula (
A1 + B1) to identify its dependencies (A1,B1). - Build a Dependency Graph: Create a data structure (like a directed graph) that maps which cells depend on which others.
- Implement a Recalculation Engine: When a cell is changed, you must traverse this graph (using an algorithm like topological sort) to find all "dirty" cells and re-evaluate them in the correct order.
This is a non-trivial computer science problem.
The uCalc Solution: The Overwrite Flag
uCalc abstracts away this entire complexity with a single, powerful feature: the overwrite flag in its definition methods. When you define a function with overwrite: true, uCalc automatically handles the dependency tracking and re-parsing for you.
Step 1: Representing Cells as Functions
We can represent each cell in our spreadsheet as a uCalc function with no parameters (e.g., A1(), B2()). The body of the function will be the cell's content—either a literal value or a formula.
// Cell A1 is a function named "A1" that returns 10.uc.DefineFunction("A1() = 10", overwrite: true);Step 2: Defining the Initial Spreadsheet
Let's define our three cells. The key is to use the overwrite: true flag (or the Overwrite ~~ command with the generic Define method). This tells uCalc that these definitions can be replaced later and that it should track dependencies.
// Define our three cells with the overwrite flaguc.DefineFunction("A1() = 10", overwrite: true);uc.DefineFunction("B1() = A1() * 2", overwrite: true);uc.DefineFunction("C1() = A1() + B1()", overwrite: true);// Let's check the initial valuesConsole.WriteLine($"Initial B1: {uc.Eval("B1()")}"); // Expected: 20Console.WriteLine($"Initial C1: {uc.Eval("C1()")}"); // Expected: 30Step 3: The Magic - Overwriting a Cell
Now, let's change the value of A1. We simply redefine it using the same overwrite flag.
// Overwrite the definition of A1uc.DefineFunction("A1() = 50", overwrite: true);Behind the scenes, uCalc detects that A1 has changed. It then automatically finds all other functions (B1 and C1) that depended on A1 and re-parses their definitions. Their internal execution plans are updated to reflect the new logic.
Now, when we evaluate B1 and C1 again, they return the new, correct values without any further work from us.
// Re-evaluate the dependent cellsConsole.WriteLine($"Updated B1: {uc.Eval("B1()")}"); // Expected: 100Console.WriteLine($"Updated C1: {uc.Eval("C1()")}"); // Expected: 150💡 Why uCalc? (Comparative Analysis)
uCalc's overwrite feature is a specialized tool that provides a massive advantage for building reactive systems.
- vs. Manual Dependency Graph: As described above, building a dependency graph manually is complex and error-prone. uCalc's engine has this logic built-in, saving hundreds of lines of code and significant development time.
- vs. Reactive Frameworks (e.g., Rx.NET): While powerful, reactive frameworks are a very different paradigm. They are designed for handling streams of events over time. uCalc's
overwritefeature is specifically tailored for the static dependency graph problem found in spreadsheets and configuration systems, offering a much simpler and more direct solution for this specific use case.
By abstracting away the complexity of dependency management, uCalc allows you to focus on defining your logic, not on the mechanics of how it's updated.
Examples
A succinct example demonstrating automatic recalculation when a source cell is changed.
using uCalcSoftware;
var uc = new uCalc();
// Define cells A1 and B1, where B1 depends on A1
uc.Define("Overwrite ~~ Function: A1() = 10");
uc.Define("Overwrite ~~ Function: B1() = A1() * 5");
Console.WriteLine($"Initial B1 value: {uc.Eval("B1()")}"); // Expected: 50
// Now, change the value of A1. B1 will update automatically.
uc.Define("Overwrite ~~ Function: A1() = 20");
Console.WriteLine($"Updated B1 value: {uc.Eval("B1()")}"); // Expected: 100
Initial B1 value: 50
Updated B1 value: 100 using uCalcSoftware; var uc = new uCalc(); // Define cells A1 and B1, where B1 depends on A1 uc.Define("Overwrite ~~ Function: A1() = 10"); uc.Define("Overwrite ~~ Function: B1() = A1() * 5"); Console.WriteLine($"Initial B1 value: {uc.Eval("B1()")}"); // Expected: 50 // Now, change the value of A1. B1 will update automatically. uc.Define("Overwrite ~~ Function: A1() = 20"); Console.WriteLine($"Updated B1 value: {uc.Eval("B1()")}"); // Expected: 100
#include
#include "uCalc.h"
using namespace std;
using namespace uCalcSoftware;
int main() {
uCalc uc;
// Define cells A1 and B1, where B1 depends on A1
uc.Define("Overwrite ~~ Function: A1() = 10");
uc.Define("Overwrite ~~ Function: B1() = A1() * 5");
cout << "Initial B1 value: " << uc.Eval("B1()") << endl; // Expected: 50
// Now, change the value of A1. B1 will update automatically.
uc.Define("Overwrite ~~ Function: A1() = 20");
cout << "Updated B1 value: " << uc.Eval("B1()") << endl; // Expected: 100
}
Initial B1 value: 50
Updated B1 value: 100 #include <iostream> #include "uCalc.h" using namespace std; using namespace uCalcSoftware; int main() { uCalc uc; // Define cells A1 and B1, where B1 depends on A1 uc.Define("Overwrite ~~ Function: A1() = 10"); uc.Define("Overwrite ~~ Function: B1() = A1() * 5"); cout << "Initial B1 value: " << uc.Eval("B1()") << endl; // Expected: 50 // Now, change the value of A1. B1 will update automatically. uc.Define("Overwrite ~~ Function: A1() = 20"); cout << "Updated B1 value: " << uc.Eval("B1()") << endl; // Expected: 100 }
Imports System
Imports uCalcSoftware
Public Module Program
Public Sub Main()
Dim uc As New uCalc()
'// Define cells A1 and B1, where B1 depends on A1
uc.Define("Overwrite ~~ Function: A1() = 10")
uc.Define("Overwrite ~~ Function: B1() = A1() * 5")
Console.WriteLine($"Initial B1 value: {uc.Eval("B1()")}") '// Expected: 50
'// Now, change the value of A1. B1 will update automatically.
uc.Define("Overwrite ~~ Function: A1() = 20")
Console.WriteLine($"Updated B1 value: {uc.Eval("B1()")}") '// Expected: 100
End Sub
End Module
Initial B1 value: 50
Updated B1 value: 100 Imports System Imports uCalcSoftware Public Module Program Public Sub Main() Dim uc As New uCalc() '// Define cells A1 and B1, where B1 depends on A1 uc.Define("Overwrite ~~ Function: A1() = 10") uc.Define("Overwrite ~~ Function: B1() = A1() * 5") Console.WriteLine($"Initial B1 value: {uc.Eval("B1()")}") '// Expected: 50 '// Now, change the value of A1. B1 will update automatically. uc.Define("Overwrite ~~ Function: A1() = 20") Console.WriteLine($"Updated B1 value: {uc.Eval("B1()")}") '// Expected: 100 End Sub End Module
A practical example simulating a small spreadsheet with interdependent cells.
using uCalcSoftware;
var uc = new uCalc();
// Define interdependent 'cells' using the Overwrite command.
uc.Define("Overwrite ~~ Function: A1() = 10");
uc.Define("Overwrite ~~ Function: B1() = A1() * 2");
uc.Define("Overwrite ~~ Function: C1() = A1() + B1()");
Console.WriteLine($"Initial C1: {uc.Eval("C1()")}"); // Should be 10 + (10 * 2) = 30
// Now, overwrite the source cell A1. All dependent cells should automatically update.
uc.Define("Overwrite ~~ Function: A1() = 50");
Console.WriteLine($"Updated B1: {uc.Eval("B1()")}"); // Should now be 50 * 2 = 100
Console.WriteLine($"Updated C1: {uc.Eval("C1()")}"); // Should now be 50 + 100 = 150
Initial C1: 30
Updated B1: 100
Updated C1: 150 using uCalcSoftware; var uc = new uCalc(); // Define interdependent 'cells' using the Overwrite command. uc.Define("Overwrite ~~ Function: A1() = 10"); uc.Define("Overwrite ~~ Function: B1() = A1() * 2"); uc.Define("Overwrite ~~ Function: C1() = A1() + B1()"); Console.WriteLine($"Initial C1: {uc.Eval("C1()")}"); // Should be 10 + (10 * 2) = 30 // Now, overwrite the source cell A1. All dependent cells should automatically update. uc.Define("Overwrite ~~ Function: A1() = 50"); Console.WriteLine($"Updated B1: {uc.Eval("B1()")}"); // Should now be 50 * 2 = 100 Console.WriteLine($"Updated C1: {uc.Eval("C1()")}"); // Should now be 50 + 100 = 150
#include
#include "uCalc.h"
using namespace std;
using namespace uCalcSoftware;
int main() {
uCalc uc;
// Define interdependent 'cells' using the Overwrite command.
uc.Define("Overwrite ~~ Function: A1() = 10");
uc.Define("Overwrite ~~ Function: B1() = A1() * 2");
uc.Define("Overwrite ~~ Function: C1() = A1() + B1()");
cout << "Initial C1: " << uc.Eval("C1()") << endl; // Should be 10 + (10 * 2) = 30
// Now, overwrite the source cell A1. All dependent cells should automatically update.
uc.Define("Overwrite ~~ Function: A1() = 50");
cout << "Updated B1: " << uc.Eval("B1()") << endl; // Should now be 50 * 2 = 100
cout << "Updated C1: " << uc.Eval("C1()") << endl; // Should now be 50 + 100 = 150
}
Initial C1: 30
Updated B1: 100
Updated C1: 150 #include <iostream> #include "uCalc.h" using namespace std; using namespace uCalcSoftware; int main() { uCalc uc; // Define interdependent 'cells' using the Overwrite command. uc.Define("Overwrite ~~ Function: A1() = 10"); uc.Define("Overwrite ~~ Function: B1() = A1() * 2"); uc.Define("Overwrite ~~ Function: C1() = A1() + B1()"); cout << "Initial C1: " << uc.Eval("C1()") << endl; // Should be 10 + (10 * 2) = 30 // Now, overwrite the source cell A1. All dependent cells should automatically update. uc.Define("Overwrite ~~ Function: A1() = 50"); cout << "Updated B1: " << uc.Eval("B1()") << endl; // Should now be 50 * 2 = 100 cout << "Updated C1: " << uc.Eval("C1()") << endl; // Should now be 50 + 100 = 150 }
Imports System
Imports uCalcSoftware
Public Module Program
Public Sub Main()
Dim uc As New uCalc()
'// Define interdependent 'cells' using the Overwrite command.
uc.Define("Overwrite ~~ Function: A1() = 10")
uc.Define("Overwrite ~~ Function: B1() = A1() * 2")
uc.Define("Overwrite ~~ Function: C1() = A1() + B1()")
Console.WriteLine($"Initial C1: {uc.Eval("C1()")}") '// Should be 10 + (10 * 2) = 30
'// Now, overwrite the source cell A1. All dependent cells should automatically update.
uc.Define("Overwrite ~~ Function: A1() = 50")
Console.WriteLine($"Updated B1: {uc.Eval("B1()")}") '// Should now be 50 * 2 = 100
Console.WriteLine($"Updated C1: {uc.Eval("C1()")}") '// Should now be 50 + 100 = 150
End Sub
End Module
Initial C1: 30
Updated B1: 100
Updated C1: 150 Imports System Imports uCalcSoftware Public Module Program Public Sub Main() Dim uc As New uCalc() '// Define interdependent 'cells' using the Overwrite command. uc.Define("Overwrite ~~ Function: A1() = 10") uc.Define("Overwrite ~~ Function: B1() = A1() * 2") uc.Define("Overwrite ~~ Function: C1() = A1() + B1()") Console.WriteLine($"Initial C1: {uc.Eval("C1()")}") '// Should be 10 + (10 * 2) = 30 '// Now, overwrite the source cell A1. All dependent cells should automatically update. uc.Define("Overwrite ~~ Function: A1() = 50") Console.WriteLine($"Updated B1: {uc.Eval("B1()")}") '// Should now be 50 * 2 = 100 Console.WriteLine($"Updated C1: {uc.Eval("C1()")}") '// Should now be 50 + 100 = 150 End Sub End Module