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 X from row 0"
  • "Multiply X by itself"
  • "Store the result in XSquared at row 0"
  • "Go to row 1"
  • "Repeat..."

You're saying:

  • "For every row, XSquared should equal X times X"

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:

  1. Clearer code — declarative recipes are easier to read than imperative loops.
  2. Faster execution — the engine evaluates formulas over batches of rows in compiled code.
  3. 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:

  1. Tracks dependencies — it knows that XSquared depends on X.
  2. Computes incrementally — each update tells the engine which rows were added, which existing rows changed (modified rows), and which columns changed. The engine computes XSquared for the added rows. For modified rows, it recomputes XSquared only when X is one of the changed columns.
  3. 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 patternDeephaven 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