A fixed collection has a maximum number of items in its type.
values {3 Int} = {10, 20}
This value has length 2 and capacity 3.
A compile-time constant can name the capacity:
capacity #Int = 4
names ~{capacity String} = {}
Different capacities create different types.
A {4 Int} does not silently become {8 Int} or growable {Int}.
{N T} is a fixed collection of T with maximum length N.
values {3 Int} = {10, 20}
capacity #Int = 4
scratch ~{capacity String} = {}
Type identity
Fixed capacity is semantic type identity.
These are distinct incompatible types:
{Int}
{4 Int}
{8 Int}
Capacity is not a growable allocation hint.
There is no implicit conversion:
- from growable to fixed
- from fixed to growable
- between different fixed capacities
Capacity syntax
Capacity in type position must be:
- a positive
Int literal - a bare visible
#Int constant name
Capacity position is not general expression position.
Arithmetic, calls, field access, const-record projection, conditionals and nested expressions are invalid there.
Name the calculation first:
base #Int = 4
larger_capacity #Int = base + 2
values ~{larger_capacity String} = {}
Capacity-only shorthand
A binding declaration with an immediate non-empty literal may infer the element type:
capacity #Int = 4
labels {capacity} = {"alpha", "beta"}
{capacity} shorthand is invalid for:
- empty literals
- non-literal initializers
- function signatures
- aliases
- fields
- return slots
Empty fixed values
An immutable binding cannot be initialised with an empty fixed literal because there is no later mutable owner path to fill it.
These are valid:
- a mutable empty fixed binding
- a fixed collection field default with an explicit field type
A fixed literal may contain fewer items than its capacity.
Its logical length is the number of stored items, not the maximum capacity.