Skip to main content
A consolidated summary of how each Tolk type is represented on the stack.

int, intN, coins

All numeric types are backed by TVM INT. A reminder: intN uses full 257‑bit precision, so any integer value fits into it. Overflow happens only at serialization.

bool

Type bool is backed by TVM INT with value -1 or 0 at runtime. The unsafe cast someBool as int is valid and produces -1 or 0.

address and any_address

Addresses are backed by TVM SLICE values containing raw binary data. A nullable address? is either TVM NULL or SLICE. The unsafe cast someAddr as slice and back is valid.

cell

Type cell is backed by TVM CELL. The unsafe cast someCell as Cell<T> is valid.

Cell<T>

Type Cell<T> is also backed by TVM CELL. The type parameter T is purely compile‑time metadata.

slice

Type slice is backed by TVM SLICE.

bitsN

Type bitsN is backed by TVM SLICE. The unsafe cast someSlice as bitsN and back is valid.

RemainingBitsAndRefs

Type “remaining” is backed by TVM SLICE. It’s actually an alias for slice, handled specially at deserialization.

builder

Type builder is backed by TVM BUILDER. Note that already written bits cannot be read. The only possible way to access builder’s data is converting it to a slice.

Structures

Fields of a structure are placed sequentially on the stack. For example, Point occupies two stack slots, and Line — four:
When constructing a Line value, four integers are placed onto the stack:
Therefore, single‑field structures have no overhead compared to plain values.

Enums

Every enum is backed by TVM INT. Tolk supports integer enums only (not addresses, for example).

Nullable types T?

Atomics like int? / address? / cell? / etc. occupy a single stack slot: it holds either TVM NULL or a value.
A nullable structure with one primitive non-nullable field can be also optimized this way:
Nullable values of multi‑slot types (e.g., Point or a tensor (bool, cell)) occupy N+1 slots: the last is used for typeid.
For every nullable type, the compiler assigns a unique typeid (e.g., 4567 for Point). That typeid is stored in an extra slot. Typeid for null is 0. Expressions such as p == null or p is Point check that typeid slot. A tricky example. A struct below, being nullable, requires an extra stack slot:

Union types T1 | T2 | ...

Unions are represented as “tagged unions”:
  • each alternative type is assigned a unique typeid (e.g., 1234 for int)
  • the union occupies N+1 stack slots, where N is the maximum size of T_i
  • (N+1)-th slot contains typeid of the current value
Thus, match is implemented as a comparison of the (N+1)-th slot, and passing/assigning a value is a bit of stack juggling.
T | null is called “nullable” and optimized for atomics: int? use a single slot. Non-atomics are handled generally, with typeid=0.

Tensors (T1, T2, ...)

Tensor components are placed sequentially, identical to struct fields. For example, (coins, Point, int?) occupies 4 slots: “INT (coins), INT (p.x), INT (p.y), INT/NULL”.

tuple

Type tuple is backed by TVM TUPLE — one stack slot regardless of the number of elements in it (up to 255).

Typed tuple [T1, T2, ...]

A typed tuple is also TVM TUPLE. Its shape is known at compile-time, but at runtime it’s the same tuple.

map<K, V>

Every map is one stack slot: either TVM NULL or CELL. Non‑empty maps (cells) have a non‑trivial bit‑level layout (follow hashmaps in TL/B).

Callables (...ArgsT) -> ResultT

A callable and continuation is backed by TVM CONT.

void and never

Both represent the absence of a value and occupy zero stack slots. For example, a void function does not place any value onto the stack.

See also