array<T>— a dynamically sized array of elements of typeT.[T1, T2, ...]— a shaped tuple with a fixed number of elements of known types.tuple— an alias forarray<unknown>, a legacy name for an untyped dynamic container.
Arrays
array<T> is a dynamically sized container that holds elements of type T:
Creating arrays with [...]
Use [...] to create an array:
T over unknown for empty arrays, specify it manually:
array<int> [...] is similar to the syntax of object creation with Point {...}, where a type hint may be omitted if clear from context.
If types within [...] are incompatible, a compilation error is reported:
Array methods
Arrays have several commonly-named methods. An IDE suggests them after a dot:array.set and others are available in the standard library.
T can be any type
An array supports any element type, including structures and unions:
T.
Internally backed by TVM tuples
An array can contain from 0 to 255 elements. It occupies one stack slot regardless of its inner size. Accessing the first 16 elements consumes less gas than greater indices, because fori >= 16 an additional instruction is required.
Arrays are assignable to each other
Anarray<T1> can be assigned to array<T2> when T1 is assignable to T2. The compiler handles all runtime transitions if required:
array<T> can be assigned to array<unknown> directly.
The unknown type
unknown represents one TVM primitive with contents unknown at compile time. Any type T can be cast to unknown and back using the as operator. If T is a primitive itself, this is a type-only cast. Otherwise, the object is packed into a sub-tuple and stored as a single slot:
array<T> is effectively converting T to unknown followed by writing that slot into a TVM tuple.
The tuple type
tuple is an alias for array<unknown>:
tuple has all the array methods: push, size, and others. Such arrays are opaque, so the push method accepts values of any type:
t.get() and t.first() return unknown. To perform meaningful operations, cast the result to a known type:
Shaped tuples
Besidesarray<T> with a dynamic size, Tolk has fixed-size containers with a known shape, called shaped tuples: [T1, T2, ...].
- They do not have methods like
push,get, orpop. - They support indexed access:
value.0,value.1, etc. - Each element can have a different type.
The [...] constructor
The literal [...] is a universal constructor that creates different types depending on context. By default, it creates an array. If the target type is known, it creates that type:
{ ... }: a type hint may exist on the variable, or the Type [...] syntax may be used:
Lisp-style lists
lisp_list<T> is a set of nested two-element TVM tuples. For instance, [1, [2, [3, null]]] represents the list [1, 2, 3].
Unlike array<T>, a lisp list can store more than 255 elements, because TVM tuples are not limited in depth. This is typically the only reason to use them: when output from a get method may grow unpredictably.
To use lists, import the @stdlib/lisp-lists file:
array.get(i) or cheap array.size:
T can be any type: complex types like Point are represented as a single slot with an intermediate conversion to unknown.
Several helper methods are available in the standard library, such as array.calculateSize and array.calculateConcatenation. These have O(N) complexity: the longer the list, the higher the gas consumption.
Conversion between arrays and composites
For composite types, generic built-in methodsT.toTuple() and T.fromTuple() convert composites to and from tuples. The length of the resulting tuple equals the number of stack slots occupied by the converted type:
Stack layout and serialization
array<T>andtupleoccupy a single stack slot: a TVMTUPLE.- Shaped tuples
[T1, T2, ...]also occupy a single TVMTUPLEslot. unknownoccupies a single stack slot.
T is serializable. The binary format uses snake references: a uint8 length followed by chained cell references containing the elements.
Raw tuples are not serializable to cells, because unknown is unserializable. But they can be returned from get methods, since contract getters operate directly on the stack.