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 directly on their corresponding literal values:
// Calling toString() defined for Int on an 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, = = 10 and = = 15.
-
A leading (or ) indicates an octal integer literal. They can include only the digits .
-
A leading (or ) indicates a binary integer literal. They can include only 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 the 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 the 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 the 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 1 to 6 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 is not an identifier and does not refer to any object. It is 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 a 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, 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 identifiers for primitive types start with an uppercase letter. User-defined composite types, such as Structs and Messages, must also 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 similarly to method calls in many other languages:
42.toString(); // toString() is a stdlib function that is defined on Int type
Static function call
A global static function or an internal function of a contract can be called from anywhere in the function body:
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
The expression initOf
computes the 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; a trailing comma is allowed);
The StateInit
is a Struct consisting of the following fields:
Field | Type | Description |
---|---|---|
code | Cell | The initial code of the contract (compiled bitcode) |
data | Cell | The initial data of the contract (parameters of the init() function or contract parameters) |
codeOf
Gas-expensive
Available since Tact 1.6
The expression codeOf
returns a Cell
containing 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 a given contract and not its StateInit
, prefer using codeOf ContractName
over initOf ContractName(param1, param2, ...)
to significantly reduce gas usage.