# FunC types (https://docs-i0yym09dy-ton-core-docs.vercel.app/llms/languages/func/types/content.md)



<Callout type="note">
  The official smart contract language of TON Blockchain is [Tolk](/llms/tolk/overview/content.md). FunC is now a **legacy** language, with its compiler no longer maintained.

  Learn how to [migrate from FunC to Tolk](/llms/tolk/from-func/tolk-vs-func/content.md). For new smart contract projects, use the [Acton toolchain](/llms/contract-dev/acton/content.md).
</Callout>

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 [#atomic-types]

Each of these types occupies a single entry on the [TVM stack](/llms/tvm/overview/content.md).

|           |                                                                                                                                                                                                                                                                                 |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `int`     | a 257-bit signed integer type. Overflow checks are enabled by default and trigger an exception.                                                                                                                                                                                 |
| `cell`    | a [TVM cell type](/llms/foundations/serialization/cells/content.md) for persistent data storage on TON Blockchain. Data is organized in a [bag of cells](/llms/foundations/serialization/boc/content.md), with each cell containing up to 1023 bits of arbitrary data and up to four references to other cells. |
| `slice`   | a 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.                                                                           |
| `builder` | a mutable structure used to construct cells by adding data and references before finalizing them into a new cell.                                                                                                                                                               |
| `tuple`   | an ordered collection of up to 255 elements, each capable of holding a value of any type.                                                                                                                                                                                       |
| `cont`    | a [TVM continuation](/llms/tvm/continuations/content.md) employed for execution flow management in [TVM instructions](/llms/tvm/instructions/content.md).                                                                                                                                                       |

### Special null value [#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()`](/llms/languages/func/stdlib/content.md). For example, in this snippet, an integer variable is declared and initialized with `null`:

```func
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](/llms/languages/func/stdlib/content.md) specifications explicitly indicate when `null` is acceptable as a valid input or output.

Example: [`cell_depth(cell c)`](/llms/languages/func/stdlib/content.md) receives a `cell` as input, and its specification states that if the input cell is `null`, the function returns `0`.

### No boolean type [#no-boolean-type]

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

* `false` is `0`, `true` is `-1`, a 257-bit integer with all bits set to `1`.
* Logical operations are performed using [bitwise operations](/llms/languages/func/operators/content.md).
* In [conditional statements](/llms/languages/func/statements/content.md), [loops](/llms/languages/func/statements/content.md), and [conditional expressions](/llms/languages/func/operators/content.md) any nonzero integer is regarded as `true`.

## Typed holes [#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:

```func
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:

```func
_ 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](/llms/languages/func/functions/content.md) for more details.

## Composite types [#composite-types]

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

### Function type [#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-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 `[]`.

<Callout>
  The empty tuple `[]` occupies one stack entry.
</Callout>

### Tensor type [#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:

```func
(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**:

```func
(int a, int b, int c) = (2, (3, 9));
```

However, this code will compile correctly:

```func
(int a, (int b, int c)) = (2, (3, 9));
```

FunC enforces strict type consistency, so only matching tensor structures are allowed.

<Callout>
  Exception: a type of the form `(A)` is considered by the type checker as the same type as `A`.
</Callout>

**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 [#polymorphism-with-type-variables]

FunC supports [polymorphic functions](https://en.wikipedia.org/wiki/Parametric_polymorphism).

Example:

```func
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: `([], [])`.

<Callout>
  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`.
</Callout>

For more details, see the [`forall` declarator](/llms/languages/func/functions/content.md) section.

## User-defined types [#user-defined-types]

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

## Type width [#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](#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.
