Book
Expressions

Expressions

Every operator in Tact forms an expression, but there's much more to uncover as Tact offers a wide range of expressive options to choose from.

Literals

Literals represent values in Tact. These are fixed values—not variables—that you literally provide in your code. All literals in Tact are expressions themselves.

You can also call extension functions defined on certain primitive types corresponding to literals right on the literal values:

// Calling toString() defined for Int on a integer literal:
42.toString();
 
// Calling asComment() defined for String on a string literal:
"Tact is awesome!".asComment();

Integer literals

Integer literals can be written in decimal (base 1010), hexadecimal (base 1616), octal (base 88) and binary (base 22) notations:

  • A decimal integer literal is a sequence of digits (09\mathrm{0 - 9}).

  • A leading 0x\mathrm{0x} (or 0X\mathrm{0X}) indicates a hexadecimal integer literal. They can include digits (09\mathrm{0 - 9}) and the letters af\mathrm{a - f} and AF\mathrm{A - F}. Note, that the case of a character does not change its value. Therefore: 0xa\mathrm{0xa} = 0xA\mathrm{0xA} = 1010 and 0xf\mathrm{0xf} = 0xF\mathrm{0xF} = 1515.

  • A leading 0o\mathrm{0o} (or 0O\mathrm{0O}) indicates a octal integer literals. They can include only the digits 07\mathrm{0 - 7}.

  • A leading 0b\mathrm{0b} (or 0B\mathrm{0B}) indicates a binary integer literal. THey can only include the digits 00 and 11.

⚠️

Be wary that in Tact integer literals with a leading 00 are still considered decimals, unlike in JavaScript/TypeScript where leading 00 indicates an octal!

Some examples of integer literals:

// decimal, base 10:
0, 42, 1_000, 020
 
// hexadecimal, base 16:
0xABC, 0xF, 0x0011
 
// octal, base 8:
0o777, 0o001
 
// binary, base 2:
0b01111001_01101111_01110101_00100000_01100001_01110010_01100101_00100000_01100001_01110111_01100101_01110011_01101111_01101101_01100101

Read more about integers and Int type on the dedicated page: Integers.

Boolean literals

The Bool type has only two literal values: true and false.

true == true;
true != false;

Read more about booleans and Bool type in the dedicated chapter: Booleans.

String literals

A string literal is zero or more characters enclosed in double (") quotation marks. All string literals are objects of String type.

"foo"
"1234"
 
// Note, that at the moment Tact strings can't have escape characters in them:
"line \n another"; // SYNTAX ERROR!, see: https://github.com/tact-lang/tact/issues/25
 
// This means, that double quotes inside strings are also prohibited:
"this \"can't be!\""; // SYNTAX ERROR!

Read more about strings and String type there: Primitive types.

null literal

The null value is written with a null literal. It's not an identifier and doesn't refer to any object. It's also not an instance of a primitive type. Instead, null represents a lack of identification and the intentional absence of any value.

let var: Int? = null; // variable, which can hold null value
var = 42;
if (var != null) {
    var!! + var!!;
}

Read more about working with null on the dedicated page: Optionals.

Identifiers

An identifier is a sequence of characters in the code that identifies a variable, constant, map and a function, as well as a Struct, Message, contract, trait, or their fields and methods. Identifiers are case-sensitive and not quoted.

In Tact, identifiers can contain latin lowercase letters (a-z), latin uppercase letters (A-Z), underscores (_) and digits (09\mathrm{0 - 9}), but may not start with a digit. An identifier differs from a string in that a string is data, while an identifier is part of the code.

Note, that when identifiers for primitive types start with an uppercase letter. Used-defined composite types, such as Structs and Messages also must be capitalized.

Instantiation

You can create instances of the following types:

struct StExample {
    fieldInit: Int = 1;
    fieldUninit: Int;
}
 
fun example() {
    StExample{ fieldUninit: 2 };               // instance with default value of fieldInit
    StExample{ fieldInit: 0, fieldUninit: 2 }; // instance with both fields set
}

Field access

You can directly access fields of the following types:

struct StExample {
    fieldInit: Int = 1;
    fieldUninit: Int;
}
 
fun example(): Int {
    let struct: StExample = StExample{ fieldUninit: 2 }; // instantiation
 
    struct.fieldInit;          // access a field
    return struct.fieldUninit; // return field value from the function
}

Extension function call

Extension functions are defined only on specific types. They can be called similar to method calls in many other languages:

42.toString(); // toString() is a stdlib function that is defined on Int type

Static function call

Anywhere in the function body, a global static function or an internal function of a contract can be called:

contract ExampleContract {
    init() {}
    receive() {
        now(); // now() is a static function of stdlib
        let expiration: Int = now() + 1000; // operation and variable declaration
        expiration = self.answerQuestion(); // internal function
    }
    fun answerQuestion(): Int {
        return 42;
    }
}

initOf

Expression initOf computes initial state (StateInit) of a contract:

//                     argument values for the init() function of the contract
//                     ↓   ↓
initOf ExampleContract(42, 100); // returns a Struct StateInit{}
//     ---------------
//     ↑
//     name of the contract

Where StateInit is a built-in Struct, that consists of:

FieldTypeDescription
codeCellinitial code of the contract (the compiled bytecode)
dataCellinitial data of the contract (arguments of init() function of the contract)