Recipes, not loops!
If you're accustomed to writing loops to transform data, stop! Deephaven works fundamentally differently, and understanding this difference early saves you frustration and helps you write better, faster code.
The fundamental paradigm shift: recipes, not loops
How you might think
In traditional Python, you tell the computer exactly how to process each element:
This loop processes one element at a time and builds a new list. You're giving step-by-step instructions for how to process the data.
How to think in Deephaven
In Deephaven, you specify what you want, not how to compute it. You write a recipe that describes the transformation, and the Deephaven engine figures out the optimal way to execute it. Table operations such as update take recipes as query strings:
There's no loop. You describe the relationship (XSquared = X * X), and the engine applies it to every row. This works the same way for arbitrarily complex operations.
When you write XSquared = X * X, you're not saying:
- "Start at row 0"
- "Read
Xfrom row 0" - "Multiply
Xby itself" - "Store the result in
XSquaredat row 0" - "Go to row 1"
- "Repeat..."
You're saying:
- "For every row,
XSquaredshould equalXtimesX"
The engine decides:
- How to split the data into batches of rows for fast processing.
- Whether to parallelize the operation.
- Which rows to recompute when data changes.
Why this matters
For static data
Even for static, one-time calculations, the recipe approach has advantages:
- Clearer code — declarative recipes are easier to read than imperative loops.
- Faster execution — the engine evaluates formulas over batches of rows in compiled code.
- Less error-prone — no manual loop management or index tracking.
For real-time data
This is the critical difference. Loops execute once and stop. Recipes keep applying to new rows as they arrive.
Watch what happens:
- The table keeps updating — new rows appear about every second.
- You wrote the recipe once, and the engine applies it to every new row.
Compare a loop that uses iter_tuple to read rows one at a time:
The engine is smart about updates
When the source data changes, the engine:
- Tracks dependencies — it knows that
XSquareddepends onX. - Computes incrementally — each update tells the engine which rows were added, which existing rows changed (modified rows), and which columns changed. The engine computes
XSquaredfor the added rows. For modified rows, it recomputesXSquaredonly whenXis one of the changed columns. - Updates results in place — it writes the new values into the result table, so you never re-run the query.
With loops, this requires significant additional infrastructure. A loop executes once and stops, so you'd have to write your own code to detect new and changed rows and recompute them. With recipes, it's automatic.
Common patterns: wrong vs. right
You've already seen the simplest pattern, creating a column from another column, in How to think in Deephaven. Two other common loops have recipe equivalents.
Pattern: conditional logic
❌ Wrong (loop approach):
✅ Right (recipe with the ternary-if operator). The operator has the form condition ? valueIfTrue : valueIfFalse:
Pattern: running calculations
❌ Wrong (loop with accumulator):
✅ Right (use update_by):
When loops are appropriate
Recipes replace loops for transforming data, but loops are still the right tool for extracting data from a table and for control flow in your own code.
✅ Extracting data from Deephaven
See the table iteration guide for details.
✅ Control flow in your Python code
A loop over ordinary Python values is fine when each iteration builds a query rather than reading table rows. Here, the loop creates one filtered table per symbol, and each table is still a live recipe.
Bridging pandas and Deephaven
Many users work with both pandas and Deephaven. Here's how to think about the transition. The habit to break is looping over DataFrame rows:
Instead, convert the DataFrame to a table once with to_table from the deephaven.pandas module, and use a recipe. Convert back with to_pandas only if you need a DataFrame again. The next chapter, Python integrations, covers both functions:
Key principle: Once you're in Deephaven, think in recipes.
Quick reference: pandas operations as recipes
These are the closest Deephaven recipes for common DataFrame operations:
| pandas pattern | Deephaven recipe |
|---|---|
df['Y'] = df['X'].apply(func) | .update("Y = func(X)") |
df['Y'] = df['X'] * 2 | .update("Y = X * 2") |
df[df['X'] > 5] | .where("X > 5") |
df['X'].rolling(window=10).mean() | .update_by(rolling_avg_tick("AvgX = X", rev_ticks=10)) |
df.groupby('G').sum() | .sum_by("G") |
Next steps
- Continue to the next chapter, Python integrations, to convert between Deephaven tables and pandas, NumPy, and other Python libraries.
- Read Think like a ninja for more examples.
- Read Vectorization and the recipe paradigm for technical details.
- See rolling aggregations with
update_byfor more recipes.