Skip to main content
Syntax of Tolk is similar to TypeScript, Rust, and Kotlin. It is designed to be straightforward to read and write. Below is a list of basic syntax elements with examples. Most sections end with a link to a detailed topic.

Imports

Imports exist at the top of the file:
import "another-file"

// symbols from `another-file.tolk` are visible
In typical workflows, an IDE inserts imports automatically (for example, when selecting an element from auto‑completion). Note: the entire file is imported, all its symbols are accessible. There are no “modules” or “exports”, all symbols must have unique (verbose) names project-wise. See: imports.

Structures

A struct Point holding two 8-bit integers:
struct Point {
    x: int8
    y: int8
}

fun demo() {
    // create an object
    val p1: Point = { x: 10, y: 20 };
    // the same, type auto-inferred
    val p2 = Point { x: 10, y: 20 };
}
  • methods are declared like fun Point.method(self), read below
  • fields can have any types: numeric, cell, union, etc. (see type system)
  • default values for fields: x: int8 = 0
  • fields can be private and readonly
  • generic structs are supported: struct Wrapper<T> { ... }
If all fields are serializable, a struct can be automatically serialized:
// makes a cell containing hex "0A14"
val c = p1.toCell();
// back to { x: 10, y: 20 }
val p3 = Point.fromCell(c);
See: structures.

Functions

A function that calculates the sum of two integers:
fun sum(a: int, b: int): int {
    return a + b;
}
  • parameter types are mandatory
  • the return type can be omitted: it will be auto-inferred, like in TypeScript
  • default values supported: fun f(b: int = 0)
  • statements inside a block are separated by semicolons ;
  • generic functions supported: fun f<T>(value: T) { ... }
  • assembler functions supported: fun f(...): int asm "..."
See: functions and methods.

Methods

A function declared fun <receiver>.name(...) is a method.
  • if the first parameter is self, it’s an instance method
  • if not self, it’s a static method
// `self` — instance method (invoked on a value)
fun Point.sumCoords(self) {
    return sum(self.x, self.y);
}

// not `self` — static method
fun Point.createZero(): Point {
    return { x: 0, y: 0 };
}

fun demo() {
    val p = Point.createZero();    // { 0, 0 }
    return p.sumCoords();          // 0
}
  • by default, self is immutable, but mutate self allows modifying an object
  • methods may be declared not only for a struct, but for any type, even a primitive:
fun int.isNegative(self) {
    return self < 0
}
See: functions and methods.

Variables

Inside functions, variables are declared with val or var keywords. The val keyword declares a variable that is assigned exactly once (immutable):
val coeff = 5;
// cannot change its value, `coeff += 1` is an error
The var keyword declares a variable that may be reassigned:
var x = 5;
x += 1;      // now 6
Variable’s type can be specified after its name:
var x: int8 = 5;
Declaring variables at the top-level (not inside functions) is supported via global keyword. See: variables.

Constants

Declaring constants is allowed at the top-level (not inside functions):
const ONE = 1
const MAX_AMOUNT = ton("0.05")
const ADMIN_ADDRESS = address("EQ...")
To group integer constants, enums are also useful.

Value semantics

Tolk follows value semantics: assignments create independent copies, and function calls do not mutate arguments unless explicitly specified.
var a = Point { x: 1, y: 2 };
var b = a;   // `b` is a copy
b.x = 99;    // `a.x` remains 1
someFn(a);   // pass a copy; `a` will not change

// but there can be mutating functions, called this way:
anotherFn(mutate a);
See: mutability.

Semicolons

  • semicolons are optional at the top-level (after imports, aliases, etc.)
  • required between statements in a function
  • after the last statement in a block, it’s also optional
// optional at the top-level
const ONE = 1
type UserId = int

// required inside functions
fun demo() {
    val x = 5;
    val y = 6;
    return x + y    // optional after the last statement
}

Comments

Like most modern languages, Tolk supports single-line (or end-of-line) and multi-line (block) comments:
// This is a single-line comment

/* This is a block comment
   across multiple lines. */

const TWO = 1 /* + 100 */ + 1    // 2

Conditional operators

fun sortNumbers(a: int, b: int) {
    if (a > b) {
        return (b, a)
    } else {
        return (a, b)
    }
}
In Tolk, if is a statement, with else if and else optional blocks. A ternary operator is also available:
val sign = a > 0 ? 1 : a < 0 ? -1 : 0;
See: conditions and loops.

Union types and matching

Union types allow a variable to hold “one of possible types”. They are typically handled by match:
fun processValue(value: int | slice) {
    match (value) {
        int => {
            value * 2
        }
        slice => {
            value.loadUint(8)
        }
    }
}
Alternatively, test a union with is or !is operators:
fun processValue(value: int | slice) {
    if (value is slice) {
        // call methods for `slice`
        return;
    }
    // value is `int`
    return value * 2;
}
Unions types are commonly used when handling incoming messages. See: union types.

While loop

while (i > 0) {
    // ...
    i -= 1;
}
The for loop does not exist. See: conditions and loops.

Assert and throw

const ERROR_NO_BALANCE = 403;

// in some function
throw ERROR_NO_BALANCE;

// or conditional throw
assert (balance > 0) throw ERROR_NO_BALANCE;
A try-catch statement is also supported, although it is not commonly used in contracts. See: exceptions.

Iterate over a map

fun iterateOverMap(m: map<int32, Point>) {
    var r = m.findFirst();
    while (r.isFound) {
        // ...
        r = m.iterateNext(r);
    }
}
See: maps.

Send a message to another contract

An outgoing message body is typically represented by a structure (for example, RequestedInfo).
val reply = createMessage({
    bounce: BounceMode.NoBounce,
    value: ton("0.05"),
    dest: someAddress,
    body: RequestedInfo { ... }
});
reply.send(SEND_MODE_REGULAR);
See: constructing and sending messages.

Contract getters

Contract getters (or “get methods”) are declared with get fun:
get fun currentOwner() {
    val storage = lazy Storage.load();
    return storage.ownerAddress;
}
See: contract getters.