Skip to main content
These functions let an activity branch, repeat, and combine conditions. Comparisons and logical operators return a boolean1 (true) or 0 (false); see Operators and precedence.

If [if]

Evaluates comparison; returns true_statement if it is true, otherwise false_statement. Any expression can appear in any position, and if calls can be nested on either branch. comparison uses one of the comparison operators:
Use == (comparison) inside conditions, not = (assignment). See Operators and precedence.
if returns whichever branch it takes, with that branch’s unit — nothing converts one branch to match the other:
The branches are not checked against each other. if(1; 5m; 10kg) returns 5 m without complaint, because only the branch taken is evaluated. Two branches that disagree dimensionally will work for every scenario that takes one of them and fail on the first scenario that takes the other. Keep both branches in the same dimension, and round-trip an activity through both.

Combining conditions

Combine comparisons with && (and), || (or), and ! (not). A good rule of thumb is to write the condition the way you would say it out loud.
Strict (>, <) and inclusive (>=, <=) comparisons differ exactly at the boundary value — choose deliberately. Nested calls cover more than two outcomes — here, a different result for “more than 10 over,” “1–10 over,” and “not over”:

Choose [choose]

Returns the expression at position index (starting with 1) — a shorthand for a chain of if statements. index must be a whole number from 1 to N, an expression that evaluates to a whole number, or a Parameter out of range error is returned.
Like if, choose returns the expression it lands on, carrying that expression’s unit, and the alternatives are not compared with one another.

Loop [loop]

Repeats expression from from to to, building a table with one row per iteration. It counts by 1 unless you pass a step, and ends when the index passes to. Two special variables are available inside the expression:
  • index — the current value of the loop counter. It starts at from and advances by step, so the default loop(1; n) runs 1, 2, … n while loop(1; 5; 2) runs 1, 3, 5.
  • last — the value from the previous iteration (0 on the first).
Any variable named index or last is ignored in favor of the loop’s own. Direction. With no step, the loop counts by 1 toward to — downward when to is below from. An explicit step must point toward to, or an input.out_of_range error is returned: loop(5; 1; -2) runs, loop(5; 1; 1) does not. A fractional step is allowed; the last row is the final index that has not passed to, so loop(5; 1; -1.1) runs 5, 3.9, 2.8, 1.7.

Looping over a unit range

from, to, and step each take a unit value as readily as a scalar, and index carries the unit into the expression. All of them must share a dimension: mixing a bare scalar with a unit value returns an input.incompatible_units error. A bound of 0 is the exception — from or to may be a bare 0 alongside unit-bearing arguments, and takes its unit from them. index is expressed in the unit of the increment — the step’s unit when you pass one, otherwise the unit of the first bound that carries one. Bounds given in other units are converted to it, so a loop from 1mo to 5yr runs sixty monthly rows. A mo is a fixed 30.4375 days and a yr a fixed 365.25 days, so a range in months rarely comes out even in another unit — 12 months is 52.18 weeks, not 52. Every mo step is that same fixed length, which is not what a calendar month does. To build a payment schedule or a monthly projection, loop over a plain count and move the date with adjdate.

Building a series

Two loop patterns recur when projecting values over time. Compound growth — a value that grows at a fixed rate each period from a first-period base:
The index - 1 exponent holds the first period at base (^ 0 is 1), and ceil guards against a fractional periods. The result is one row per period. Running total — a cumulative sum across an existing table, with last as the accumulator:
Each row holds the total through that period, so the final row — item(result; length(result)) — is the all-up total. See item and length in Table functions.