Skip to main content
Tolk supports structures — similar to TypeScript classes, but designed to operate on TVM.
struct Point {
    x: int
    y: int
}

fun calcMaxCoord(p: Point) {
    return p.x > p.y ? p.x : p.y
}

fun demo() {
    // declared using object-literal syntax
    var p: Point = { x: 10, y: 20 };
    calcMaxCoord(p);

    // constructed using object-literal syntax
    calcMaxCoord({ x: 10, y: 20 });
}

Two identical structures are not assignable

struct SomeA { v: int }
struct SomeB { v: int }

fun acceptA(a: SomeA) {}

fun demo(a: SomeA, b: SomeB) {
    b = a;      // error, can not assign `SomeA` to `SomeB`
    acceptA(b); // error, can not pass `SomeB` to `SomeA`
}
Even though A and B have identical body, they represent distinct types. Analogy: a struct behaves like a TypeScript class, not interface. Typing is nominal, not structural.

The compiler infers the type from context

In a snippet below, the compiler understands that { ... } is StoredInfo because of parameter’s type:
fun store(info: StoredInfo) {
    // ...
}

fun demo() {
    store({
        counterValue: ...,
        ownerAddress: ...,
    });
}
The same applies to return values and assignments:
fun loadData(): StoredInfo {
    return {
        counterValue: ...,
        ownerAddress: ...,
    }
}

fun demo() {
    var s: StoredInfo = { counterValue, ... };
    var s: (int, StoredInfo) = (0, { counterValue, ... });
}

Explicit type hints are also available

Besides the plain { ... } syntax, the form StructName { ... } may be used, similar to Rust. The snippet below is equivalent to the above:
fun loadData() {
    return StoredInfo {
        counterValue: ...,
        ownerAddress: ...,
    }
}

fun demo() {
    var s = StoredInfo { counterValue, ... };
    var s = (0, StoredInfo { counterValue, ... });
}
When neither contextual information nor an explicit type hint is available, the type cannot be inferred and an error is produced.
val o = { x: 10, y: 20 };    // error, what type is it?

Methods for structures

Methods are declared as extension functions, similar to Kotlin:
fun Point.calcSquare(self) {
    return self.x * self.y
}
Notice the first self parameter. Without it, a method will be static. By default, self is immutable. The form mutate self enables mutation. Read Functions and methods.

Prefixes do not affect typing or layout

Serialization prefixes struct (0x...) Name affect serialization only:
struct (0x12345678) CounterIncrement {
    byValue: uint32
}

fun demo(inc: CounterIncrement) {
    // the only field; the prefix is not a property
    inc.byValue
    // `inc` is still one TVM INT on the stack
}

Syntax of structures

  • Shorthand syntax { x, y } is available
  • Default values for fields
  • private and readonly fields
  • Serialization prefixes (opcodes)
Read Syntax of structures and fields.

Stack layout and serialization

Fields are placed on the stack sequentially and are serialized in the same order. If a struct has a prefix (opcode), it is written first. For details, follow TVM representation and Serialization.