Softanza
StartFrançais
Softanza
Core data & language

Tables & data

Broad unified data frame with a pattern language, but no join, and a group-by that runs outside the engine.

2 Strong · 6 Solid · 3 Partial · 1 Emerging

Measured against: pandas · Polars · DuckDB · Folders: base/table(opens in a new tab) · base/data(opens in a new tab) · For programmers: this area's reference

eight regions of Niger as a table the engine typeset
eight regions of Niger as a table the engine typeset. rendered on 2026-10-01 at 04:00 by the site's render script tools/areas.ring, run inside the library at commit 0e72e2e2c · the source(opens in a new tab)

Rethought from first principles

What Softanza kept from what works, and what it rethought, as the library wrote it down in its design documents and narrations.

The Softanza wayA table is a grid people read like a spreadsheet — named columns, rows and cells — and every column is a list you can question.

Kept from the best practice

  • Data is stored by column, because columns have names and rows do not, and data analysis treats every variable as a column. source(opens in a new tab)
  • Familiar spreadsheet functions (SUM, AVERAGE, MIN, MAX, PRODUCT), grouping with aggregates, and pivot tables work on a table directly. source(opens in a new tab)
  • Standard formats in and out: CSV, JSON and HTML tables, plus real SQL through an embedded SQLite database (stzDatabase). source(opens in a new tab)

Rethought

  • Methods use plain words — AddRow, RemoveCol, Cell, FindInCol — that follow how people think about tables, rather than a technical data-frame vocabulary, so learning stays gentle. source(opens in a new tab)
  • A column is a list: whatever you ask a list — sum it, filter it by a condition — you can ask a column, so knowing lists already means knowing tables. source(opens in a new tab)
  • Tables are validated by pattern: one stzTablex expression states shape, unique keys, missing values and averages, instead of procedural checking code. source(opens in a new tab)
  • A table hands a column to the statistics object instead of recomputing statistics itself, because duplicated definitions drift: two classes once disagreed on a variance (4 versus 4.57). source(opens in a new tab)

One enormous unified class, 2,517 methods with eleven sibling caps merged into a single stzTable, with engine-backed sort, aggregates, calculated columns, describe and pivot, plus a distinctive multi-table TableX pattern-query language. Measured against pandas, Polars and DuckDB it has three real holes: there is no join at all; group-by and filter run Haro-side even though engine bridges for both sit exported-but-unused; and the columnar engine is used per-operation, not as the live store.

What a crafter does with it, and what stands out

  • A multi-table TableX pattern-query language with no direct peer
  • A copy-free index-permutation engine sort
  • Engine-first calculated columns, compile-once over all rows, guarded at 50k rows
  • Eleven sibling caps merged into one stzTable namespace

What is owed

  • Add joins: there is no join anywhere in the tables lane
  • Wire group-by and filter to the engine bridges already compiled and exported
  • Finish the 11-to-1 fidelity grind (150 of 251 legacy tests error)
  • Missing-data toolkit (fillna / dropna) and melt / unpivot

The Softanza way, run

What Softanza does differently in this area, shown by code taken from its narrations and guards, and run for this page.

A column is a list, so it can be summed or searched with a condition like any list.

Softanza
oT = new stzTable([
	[ :DISH, :PRICE, :ORDERS ],
	[ "tea",  200, 6 ],
	[ "rice", 500, 3 ],
	[ "fish", 900, 2 ]
])
? StzListQ(oT.Col(:ORDERS)).Sum()
? @@( StzListQ(oT.Col(:PRICE)).FindW("{ @item > 400 }") )
Output
11
[ 2, 3 ]

run on 2026-10-01 21:17 inside the library at commit 0e72e2e2c; taken from base/education/program/courses/elementary-introduction/chapters/10-when-code-meets-cells.en.md(opens in a new tab)

A table built column by column answers statistics such as the median and first quartile through the shared statistics engine.

Softanza
oT = new stzTable([
	[:age,    [20, 25, 30, 35, 40]],
	[:income, [30, 42, 51, 66, 80]],
	[:city,   ["a", "b", "c", "d", "e"]]
])
Then("MedianCol(age) is 30", oT.MedianCol(:age), 30)
Then("Q1Col(age) is 25", oT.Q1Col(:age), 25)
Output
  THEN  MedianCol(age) is 30  [PASS]
  THEN  Q1Col(age) is 25  [PASS]

run on 2026-10-01 21:17 inside the library at commit 0e72e2e2c; taken from base/test/table/table_statistics_narrated.ring(opens in a new tab)

The articles of this area (2)

The lanes, one by one

Lanes and their notes are quoted as they were read at the source, on Read from the source on 2026-09-16.

Two readings. The Atlas card (v21, 2026-09-30) says 2 Strong, 6 Solid, 3 Partial, 1 Emerging; the group page, read Read from the source on 2026-09-16, rates its lanes 2, 7, 3, 0. The lanes below are the group page's; the card is the more recent reading.

Calculated and derived columns
Strong
AddCalculatedCol with an @(:ColName) formula lowered engine-first through StzEngineListEvalRows (compile-once), Haro eval() fallback; guarded at 50k rowsStzEngineListEvalRows; narrated calc-column guard
Sort and order
Strong
SortOn(col) via StzEngineTableSortOn to table.zig sortOnColumn: an index-permutation pdq sort that moves companion columns without copying row objectstable.zig sortOnColumn
Construction and I/O
Solid
From list-of-columns or hashlist; CSV, JSON, HTML round-trips; SQLite via stzDatabase; no Parquet/Arrow/Excel; FromJson is #TODO; iscsv guards fail (collision)base/file/stzCSV; test/csv
Columns, typing and access
Solid
Per-column type_hint and per-cell tags in table.zig; Cell/Row/Col/Section access; legacy aliases (colsection, rowz, cellsincol) error after the 11-to-1 mergetable.zig
Select, project, filter
Solid
Filter, FilterBy, FilterW/FilterWXT and TableX multi-table querying over stzListOfTables; all Haro-side, the engine FilterRows exists but is never called
Reshape: pivot and transpose
Solid
stzPivotTable + stzPivotTableShow engine-backed via StzEnginePivotCrossTab / PivotGroupBy, plus Transpose variants; no melt / unpivot / wide-to-longStzEnginePivotCrossTab / PivotGroupBy
Describe and summary stats
Solid
Describe() engine-backed through frame.zig (StzEngineFrameDescribeAll: 8 stats per column) plus whole-table regression (StzEngineFrameRegression)frame.zig StzEngineFrameDescribeAll
The unified hierarchy and TableX
Solid
Eleven caps merged into one stzTable namespace, old classes survive as ~1 KB shells; TableX pattern language over tables; 150 legacy tests left erroring
Aggregates (scalar column)
Solid
StzEngineTableSumCol / AvgCol / MinCol / MaxCol / ProductCol / CountNonNull: cache-friendly columnar scans, engine-backedStzEngineTableSumCol et al.
Group-by (grouped aggregation)
Partial
GroupBy/GroupByXT work as pure Haro row-wise hash-string keying; the engine groupByAggregate (GroupBy) has O(n) hashed keys but stzTable never calls ittable.zig groupByAggregate / GroupBy (unused)
Missing-data handling
Partial
Per-cell null tags, AllItemsAreNull, CountNonNull and TableX null checks; no fillna / dropna / interpolate / forward-fill family
Columnar scale and SQL
Partial
A real columnar engine (table.zig) and SQLite via stzDatabase, but the Haro table marshals row-wise @aContent per operation; no query planner, no lazy executiontable.zig; db.zig