diff --git a/language/data.md b/language/data.md index e568dd0..9e32c84 100644 --- a/language/data.md +++ b/language/data.md @@ -45,7 +45,7 @@ The operator surface is small. | Form | Meaning | | ----------------- | --------------------------------------------------------------------------------------- | | `expr.identifier` | Property access. Available on records, variant struct cases, `AnyAsset`, and `UtxoRef`. | -| `expr[expr]` | List indexing. The index expression must have type `Int`. | +| `expr[expr]` | Indexing. For a `List` the index is any `Int` expression; for a `Tuple<...>` the index must be an integer literal in range, and the result type is that position's type. | | `!expr` | Arithmetic negation. Applies to `Int`. | | `a * b` | Multiplication. `Int * Int` multiplies integers; `AnyAsset * Int` (and `Int * AnyAsset`) scales asset quantities. | | `a / b` | Integer division, truncating toward zero (`7 / 2` is `3`). `Int / Int` divides integers; `AnyAsset / Int` divides each asset quantity. Does not commute (`Int / AnyAsset` is invalid). Dividing by `0` is an error. | @@ -115,17 +115,22 @@ MyRecord { Fields written explicitly take precedence; remaining fields are taken from `source`. -### Lists and maps +### Lists, maps, and tuples ```tx3 [1, 2, 3] // List [] // empty list — type from context {1: "Value1", 2: "Value2"} // Map + +(1, 0xFF) // Tuple +(1, 0xFF, true) // Tuple ``` A `Map` literal must contain at least one entry; the first entry fixes the key and value types. +A tuple literal is two or more comma-separated expressions in parentheses, and its element types are taken positionally. `(e)` is grouping (not a one-tuple) and `()` is the unit value. Read an element back with a literal index — `pair[0]`, `pair[1]` — exactly like list indexing. See [Tuples](./types#tuples). + ## Property access Records and variant struct cases expose their named fields. `AnyAsset` and `UtxoRef` expose a fixed set of built-in properties: diff --git a/language/types.md b/language/types.md index a24b4f0..34fff44 100644 --- a/language/types.md +++ b/language/types.md @@ -52,6 +52,35 @@ type Datum { } ``` +### Tuples + +`Tuple` is a fixed-arity, positionally-typed group of values. Unlike a `List`, each position can have a different type; unlike a record, the positions are unnamed. A tuple always has **two or more** elements. + +```tx3 +type Datum { + pair: Tuple, + triple: Tuple, +} +``` + +You build a tuple by writing two or more comma-separated expressions in parentheses; the element types are taken positionally: + +```tx3 +(42, 0xDEADBEEF) // Tuple +(quantity, name, true) // Tuple +``` + +`(e)` (a single parenthesized expression) is just grouping, and `()` is the unit value — neither is a tuple, which is why tuples start at two elements. + +Read an element back by **positional index**, using the same bracket syntax as a list: + +```tx3 +pair[0] // the Int +pair[1] // the Bytes +``` + +The index must be an integer literal within range — a tuple cannot be indexed by a runtime value, since each position may have a different type, and an out-of-range index is a compile error. + ## User-defined types User-defined types are introduced with the `type` keyword. There are three shapes. @@ -139,6 +168,6 @@ Cyclic aliases (`type A = B; type B = A;`) are rejected. ## Type equivalence -Two types are equivalent if they are the same primitive, the same `List` (with equivalent `T`), the same `Map` (with equivalent `K` and `V`), or refer to the same user-defined type after alias chasing. +Two types are equivalent if they are the same primitive, the same `List` (with equivalent `T`), the same `Map` (with equivalent `K` and `V`), the same `Tuple<...>` (same arity, with each position's type equivalent), or refer to the same user-defined type after alias chasing. Tuple equivalence is structural and order- and arity-sensitive: `Tuple` and `Tuple` are different types, and neither equals `Tuple`. There are no implicit conversions. `Int` does not silently turn into `Bytes`, and `Bytes` does not silently turn into `Address`, `UtxoRef`, or `AnyAsset`. Where a position expects a specific type, the expression must already have that type.