Skip to main content
FunC offers a range of built-in types covering all the types the TVM has. On the other hand, FunC has no custom user-defined types like records or classes.

Atomic types

Each of these types occupies a single entry on the TVM stack.
inta 257-bit signed integer type. Overflow checks are enabled by default and trigger an exception.
cella TVM cell type for persistent data storage on TON Blockchain. Data is organized in a bag of cells, with each cell containing up to 1023 bits of arbitrary data and up to four references to other cells.
slicea read-only view of a cell that allows sequential access to its data and references. A cell can be converted into a slice, extracting stored bits and references without modifying the original cell.
buildera mutable structure used to construct cells by adding data and references before finalizing them into a new cell.
tuplean ordered collection of up to 255 elements, each capable of holding a value of any type.
conta TVM continuation employed for execution flow management in TVM instructions.

Special null value

Any atomic type allows the special value null which represents the absence of an actual value of that type. For example, a function that searches the position of an integer in a list may return null to signify that it could not find the integer. The null value can be obtained by calling the function null(). For example, in this snippet, an integer variable is declared and initialized with null:
int a = null();   ;; a has value null
Since null is a valid value for any atomic type, keep the following in mind when working with functions:
  • Functions that return an atomic type may return null.
  • Functions that expect an atomic type as input could also accept null.
  • For library functions specifications explicitly indicate when null is acceptable as a valid input or output.
Example: cell_depth(cell c) receives a cell as input, and its specification states that if the input cell is null, the function returns 0.

No boolean type

FunC does not have a boolean type. Instead, booleans are represented as integers:

Typed holes

FunC supports type inference through the type holes: _ and var serve as placeholders resolved during type checking; _ is for functions, and var is for variables. Example:
var x = 2;
The type checker determines that x is of type int since 2 is an int. As another example, in the following function declaration:
_ someFunction(int a) {
  return a + 1;
}
the type checker infers that _ has type int, as the return expression a + 1 is of type int. See Function declarations for more details.

Composite types

To represent non-atomic, composite types, simpler types can be combined with the following three operations.

Function type

A functional type is written in the form A -> B, where:
  • A is the input type, which is called domain.
  • B is the output type, which is called codomain.
For example, the type int -> cell represents a function that:
  • Takes an integer as input.
  • Returns a cell as output.
Like in functional programming, it is possible to declare function types which have in their domain and codomain other function types. For example, (int -> int) -> int is a function with domain int -> int and codomain int. Similarly, cell -> (slice -> slice) is a function with domain cell and codomain slice -> slice

Tuple type

Tuple types in FunC are written in the form [A, B, ...] and represent TVM tuples with fixed length and known component types at compile time. A tuple occupies one entry on the TVM stack, even if it is a zero-length tuple. For example, [int, cell] defines a tuple with exactly two elements:
  • The first element is an integer.
  • The second element is a cell.
The type [] represents an empty tuple. There is only one value of this type, the empty tuple, which is also written as [].
The empty tuple [] occupies one stack entry.

Tensor type

Tensor types represent ordered collections of values and are written in the form (A, B, ...). These types occupy multiple TVM stack entries, unlike atomic types, which use a single entry. Example: A function foo of type int -> (int, int) takes one integer as input and returns two integers as output, each one occupying a stack entry. Example call:
(int a, int b) = foo(42);
Internally, the function consumes one stack entry and produces two. Type representation: Values (2, (3, 9)) of type (int, (int, int)) and (2, 3, 9) of type (int, int, int) are stored identically as three stack entries containing the values 2, 3, and 9, respectively. However, FunC treats (int, (int, int)) and (int, int, int) as distinct types. The following code will not compile:
(int a, int b, int c) = (2, (3, 9));
However, this code will compile correctly:
(int a, (int b, int c)) = (2, (3, 9));
FunC enforces strict type consistency, so only matching tensor structures are allowed.
Exception: a type of the form (A) is considered by the type checker as the same type as A.
Special case: unit type() The unit type () is used to indicate that:
  • A function does not return a value, or
  • A function takes no arguments
The unit type () has a single value, also written as (), occupying zero stack entries. Examples
  • print_int has the type int -> (), meaning it takes an integer but returns nothing.
  • random has the type () -> int, meaning it takes no arguments but returns an integer.

Polymorphism with type variables

FunC supports polymorphic functions. Example:
forall X -> (X, X) duplicate(X value) {
  return (value, value);
}
Here, X is a type variable that allows the function to operate on values of any type. Type variables are declared between forall and ->. The function receives a value of type X, and duplicates this value to return a value of type (X, X). For example,
  • Calling duplicate(6) produces (6, 6).
  • Calling duplicate([]) produces two copies of an empty tuple: ([], []).
Type variables in polymorphic functions cannot be instantiated with tensor types. The only exception is a tensor of a single element (a), where a is not a tensor type itself. The compiler treats (a) as equivalent to a.
For more details, see the Polymorphism with forall section.

User-defined types

FunC does not support defining custom types beyond the type constructions described above.

Type width

Every value in FunC occupies a certain number of stack entries. If this number is consistent for all values of a given type, it is called the type width. For example, all atomic types have a type width of 1, because all their values occupy a single stack entry. The tensor type (int, int) has type width 2, because all its values occupy 2 stack entries.