Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Build and scan columnar records

Declare a class normally, then create a clist to store its fields in separate columns. This example reserves space for three readings, averages their temperatures, and updates and copies a row:

class Reading:
    station: i64
    temperature: f64

def add(total: f64, temperature: f64) -> f64:
    total + temperature

def main() -> Result[(), AllocError | AppendError[Reading] | IoError]:
    mut readings = clist[Reading].with_capacity(3)?
    readings.append(Reading(10, 18.0))?
    readings.append(Reading(20, 21.0))?
    readings.append(Reading(30, 24.0))?
    total = readings.column(Reading.temperature).fold(0.0, add)
    print(total / f64(len(readings)))?
    readings[0].temperature = 19.0
    match readings.copy_row(0):
        case Some(reading):
            print(reading.station, reading.temperature)?
        case Nothing:
            ()
    Ok(())
21.0
10 19.0

Reading.temperature selects that field’s column. The pipeline borrows the collection and yields scalar values, so add takes f64 directly. Reserving capacity makes the three appends allocation-free after construction. Errors from append retain the submitted reading; this example propagates that error so callers can decide whether to retry.

A column pipeline is consumed once. While it remains live, the collection cannot be changed or moved. Create a new column pipeline for another pass. copy_row gathers a row’s fields from the separate columns into an independent ordinary object. It allocates nothing, but gathering all the fields can cost more than accessing a record in an ordinary list. Changing the copy does not change the stored row. Use a column for a selected-field calculation and a row copy when you actually need the complete object.

The primitive-only restriction keeps this first version’s ownership and packed storage model simple and sound. Prefer an ordinary list for strings, nested objects, row references, or workloads that usually access whole objects. Indexed field access and row copying compile to direct scalar memory operations, with bounds checks. This avoids dispatching through a generic runtime helper for each field, but does not make every access pattern faster. Use column pipelines for repeated scans when the calculation needs selected fields.

Next, count matching integer values with an automatically optimized column pipeline. See the columnar-list reference for the allocation, borrowing and representation contracts.