4. Lists, records, and pipe-tables

The composite shapes: ordered lists, named-field records, and compact row tables.

After this lesson you can

- Author lists and bare record literals - Declare a @table row type and write pipe-rows - Know when a table beats a list of records

Before you start: Primitive types and literals

A list is square brackets over any element type: tags = ["alpha", "beta"]. A record is named fields in braces — and when the declared type is known, a bare record literal ({ name: "Ops team", contact: "..." }) coerces to it, so you rarely spell the type name at the value site.

When many values share one shape, pipe-table syntax keeps them readable: declare the row type with @table("kind"), give a block a @children("kind") field, then write the field as name: followed by | cell | cell | rows — each row becomes one record.

§ 1Exercise: A catalogue with all three

Author a document holding a list, a record, and a pipe-table of users, then read the list back.

wcl
type Owner { name: utf8  contact: utf8 }

@table("user")
type User {
  name:    utf8
  age:     u32
  enabled: bool
}

@block("db")
type Db {
  @inline(0) id: identifier
  @children("user") users: list<User>
}

@document
type Doc {
  tags:  list<utf8>
  owner: Owner
  @child("db") db: Db
}

tags  = ["alpha", "beta", "gamma"]
owner = { name: "Ops team", contact: "ops@example.com" }

db production {
  users:
    | "alice" | 30 | true  |
    | "bob"   | 25 | false |
    | "cara"  | 42 | true  |
}

Expected result

wcl check prints OK, and wcl eval doc.wcl tags prints ["alpha", "beta", "gamma"].

Hint

Table cells are expressions in the row type's field order: string, number, bool here. Add a fourth cell to a row and the shape no longer lines up.