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 ), hexadecimal (base ), octal (base ) and binary (base ) notations:
-
A decimal integer literal is a sequence of digits ().
-
A leading (or ) indicates a hexadecimal integer literal. They can include digits () and the letters and . Note, that the case of a character does not change its value. Therefore: = = and = = .
-
A leading (or ) indicates a octal integer literals. They can include only the digits .
-
A leading (or ) indicates a binary integer literal. THey can only include the digits and .
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";
Tact strings support a range of escape sequences starting with a backslash \\
character:
\\
— literal backslash\"
— double quote\n
— newline\r
— carriage return\t
— tab\v
— vertical tab\b
— backspace\f
— form feed\x00
through\xFF
— code point, must be exactly two hex digits long\u0000
through\uFFFF
— Unicode code point, must be exactly four hex digits long\u{0}
through\u{FFFFFF}
— Unicode code point, can be from to hex digits long
// \\"escape \\ if \\ you \\ can \\";
// \""this \"literally\" works";
// \n"line \n another line";
// \r"Shutters \r Like \r This \r One";
// \t"spacing \t granted!";
// \v"those \v words \v are \v aligned";
// \b"rm\b\bcreate!";
// \f"form \f feed";
// \x00 - \xFF"this \x22literally\x22 works"; // \x22 represents a double quote
// \u0000 - \uFFFF"danger, \u26A1 high voltage \u26A1"; // \u26A1 represents the ⚡ emoji
// \u{0} - \u{FFFFFF}"\u{1F602} LOL \u{1F602}"; // \u{1F602} represents the 😂 emoji
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 valuevar = 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 may contain Latin lowercase letters a-z
, Latin uppercase letters A-Z
, underscores _
, and digits , but may not start with a digit. No other symbols are allowed, and Unicode identifiers are prohibited.
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() { // Instance with default value of fieldInit StExample{ fieldUninit: 2 };
// Instance with both fields set StExample{ fieldInit: 0, fieldUninit: 2, // trailing comma is allowed };}
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 { 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
Gas-expensive
Expression initOf
computes initial state, i.e. 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// ↓// ---------------initOf ExampleContract( 42, // first argument 100, // second argument, trailing comma is allowed);
The StateInit
is a Struct consisting of the following fields:
Field | Type | Description |
---|---|---|
code | Cell | initial code of the contract (compiled bitcode) |
data | Cell | initial data of the contract (parameters of init() function) |
codeOf
Gas-expensive
Available since Tact 1.6 (not released yet)
Expression codeOf
returns a Cell
with the code of a contract:
codeOf ExampleContract; // a Cell with ExampleContract code// ---------------// ↑// name of the contract
If codeOf
is used for the current contract, its result is equivalent to calling myCode()
.
contract ExampleContract { receive() { myCode() == codeOf ExampleContract; // true }}
If you only need the code of the given contract and not its StateInit
, prefer using codeOf ContractName
over initOf ContactName(param1, param2, ...)
to significantly reduce gas usage.