# FunC functions (https://docs-kyrm16yq7-ton-core-docs.vercel.app/llms/languages/func/functions/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>

Every function declaration or definition follows a common pattern. The general form is:

```func
[<forall declarator>] <return type> <function name>(<comma separated function args>) <specifiers> <function body>
```

where `[ ... ]` represents an optional entry. Here,

* `<forall declarator>` is the [`forall` declarator](#forall-declarator), which declares that the function is [polymorphic](https://en.wikipedia.org/wiki/Parametric_polymorphism). This is optional.
* `<return type>` is the [return type](#return-type) of the function.
* `<function name>` is the [function name](#function-name).
* `<comma separated function args>` is a comma separated list of [function arguments](#function-arguments), each argument consisting on a type and the argument's name.
* `<specifiers>` are [specifiers](#specifiers) that instruct the compiler on how to process the function.
* `<function body>` is the actual [function body](#function-body), which can be of three kinds: an [empty body](#empty-body), an [assembler body](#assembler-body), or a [standard body](#standard-body).

## Return type [#return-type]

The return type can be any atomic or composite type, as described in the [Types](/llms/languages/func/types/content.md) section.

For example, the following functions are valid:

```func
int foo() { return 0; }
(int, int) foo'() { return (0, 0); }
[int, int] foo''() { return [0, 0]; }
(() -> int) foo'''() { return foo; }
() foo''''() { return (); }
```

FunC also supports **type inference** with the use of underscore `_` as the return type.

For example:

```func
_ divAndMod(int m, int n) {
  return (m /% n);
}
```

There, the function `divAndMod` has the inferred type `(int, int) -> (int, int)`. The function computes the division and modulo of the parameters `m` and `n` by using the [division and modulo](/llms/languages/func/operators/content.md) operator `/%`, which always returns a two-element tensor `(int, int)`.

## Function name [#function-name]

A function name can be any valid [identifier](/llms/languages/func/literals/content.md). Additionally, it may start with the symbols `.` or `~`, which have specific meanings explained in the [special function call notation](/llms/languages/func/expressions/content.md) section. Specifically, refer to this [section](/llms/languages/func/expressions/content.md) to understand how the symbols `.` or `~` affect the function name.

For example, `udict_add_builder?`, `dict_set`, and `~dict_set` are all valid function names, and each is distinct. These functions are defined in [stdlib.fc](/llms/languages/func/stdlib/content.md).

FunC reserves several function names. See the [reserved functions](/llms/languages/func/special-functions/content.md) article for more details.

## Function arguments [#function-arguments]

A function can receive zero or more argument declarations, each declaration separated by a comma. The following kinds of argument declarations are allowed:

* Ordinary declaration: an argument is declared using **its type** followed by **its name**. Example:

  ```func
  int foo(int x) {
    return x + 2;
  }
  ```

  Here, `int x` declares an argument named `x` of type `int` in function `foo`.

  An example that declares multiple arguments:

  ```func
  int foo(int x, int y) {
    return x + y;
  }
  ```

  An example that declares no arguments:

  ```func
  int foo() {
    return 0;
  }

  ```

* Unused argument declaration: only its type needs to be specified. Example:

  ```func
  int first(int x, int) {
    return x;
  }
  ```

  This is a valid function of type `(int, int) -> int`, but the function does not use its second argument.

* Argument with inferred type declaration: If an argument's type is not explicitly declared, it is inferred by the type-checker. For example,

  ```func
  int inc(x) {
    return x + 1;
  }
  ```

  This defines a function `inc` with the inferred type `int -> int`, meaning `x` is automatically recognized as an `int`.

<Callout>
  Even though a function may appear to take multiple arguments, it takes a single [tensor type](/llms/languages/func/types/content.md) argument. For more details on this distinction, refer to the [function call](/llms/languages/func/expressions/content.md) section.

  However, for convenience, the individual components of this tensor are conventionally referred to as function arguments.
</Callout>

## Specifiers [#specifiers]

In FunC, function specifiers modify the behavior of functions. There are three types:

1. `impure`
2. Either `inline` or `inline_ref`, but not both
3. `method_id`

One, multiple, or none can be used in a function declaration. However, they must appear in the order of the above list, e.g., `impure` must come before `inline` and `method_id`, `inline_ref` must come before `method_id`, etc.

### `impure` specifier [#impure-specifier]

The `impure` specifier indicates that a function has side effects, such as modifying contract storage, sending messages, or throwing exceptions. If a function is not marked as `impure` and its result is unused, the FunC compiler may delete the function call for optimization.

For example, the [stdlib.fc](/llms/languages/func/stdlib/content.md) function [`random`](/llms/languages/func/stdlib/content.md) changes the internal state of the random number generator:

```func
int random() impure asm "RANDU256";
```

The `impure` keyword prevents the compiler from removing calls to this function:

```func
var n = 0;
random();     ;; Even though the result of random is not used,
              ;; the compiler will not remove this call
              ;; because random has the impure specifier.
```

### Inline specifier [#inline-specifier]

A function marked as `inline` is directly substituted into the code wherever it is called, eliminating the function call overhead. Recursive calls are not allowed for inline functions.

For example:

```func
(int) add(int a, int b) inline {
    return a + b;
}
```

Since the `add` function is marked with the `inline` specifier, the compiler substitutes `add(a, b)` with `a + b` directly in the code.

For instance, the compiler will replace the following code:

```func
var a = 1;
var b = 2;
var n = add(a, b);
```

with this code:

```func
var a = 1;
var b = 2;
var n = a + b;
```

### `inline_ref` specifier [#inline_ref-specifier]

When a function is marked with the `inline_ref` specifier, its code is stored in a separate cell. Each time the function is called, the TVM executes a `CALLREF` command, which loads the code stored in the referenced cell and executes the function code.

To give you a very high level idea on how to visualize this, think how programs are stored in the blockchain. Anything in the blockchain is a cell. A program is a [directed acyclic graph (DAG)](/llms/foundations/whitepapers/tblkch/content.md) of cells. Each cell stores TVM instructions, and can have up to 4 references to other cells. Each one of those references represent code that the TVM can jump to.

So, you can picture a program like this:

```text
Cell 1

instruction 1
instruction 2
.....
call reference A
.....
instruction n
----------------------------------------
Reference to cell A | Reference to cell B |
```

where `Reference to cell A`, and `Reference to cell B` are references to other cells containing further code of the program. When the TVM executes the instruction `call reference A`, the TVM loads the cell referenced by `Reference to cell A` and executes the cell.

When a function is marked as `inline_ref`, its code is placed in a separate cell, name it `C`. Then, everywhere the function is called in the original program,
it is replaced with a `call reference C`. Then, the reference to `C` is added to the original program as a cell reference.

More concretely, imagine the following program:

```func
int foo() inline_ref {
  return 1;
}

int main() {
  return (foo() + foo());
}
```

Then, this would create two cells, one storing the code of the `main` function, call it cell `M`; and another cell storing the code of the `foo` function, because it is marked as `inline_ref`, call it cell `F`. The two calls to `foo` inside `main` will be replaced by reference calls to `F`.

And the reference to `F` is added as a reference in cell `M`:

```text
Cell M

call reference to F
call reference to F
ADD
----------------------------------------
Reference to F |


Cell F

1 PUSHINT
```

When `call reference to F` executes, the TVM loads the cell for `F` and executes it.

As the example suggests, contrary to the `inline` specifier, the code for `foo` is not duplicated, because the two calls for `foo` are loading the same cell. As such, `inline_ref` is generally more efficient regarding code size.

The only case where `inline` might be preferable is if the function is called just once, because loading cell references costs gas.

However, recursive calls to `inline_ref` functions remain impossible, as TVM cells do not support cyclic references.

### `method_id` specifier [#method_id-specifier]

In a TVM program, every function has an internal integer ID that identifies it uniquely. These IDs are necessary because of the way the TVM calls functions within a program: it uses a dictionary where each key is a function ID that maps to the corresponding function code. When the TVM needs to invoke a particular function, the TVM looks up the ID in the dictionary and executes the corresponding code.

By default, functions are assigned sequential numbers starting from `1`. If a function has the `method_id` specifier, the compiler will compute an ID using the formula `(crc16(<function_name>) & 0xffff) | 0x10000` instead. Additionally, such function becomes a get-method (or getter method), which are functions that can be invoked by its name in lite client or TON explorer.

The `method_id` specifier has the variant `method_id(<some_number>)`, which allows you to set a function's ID to a specific number manually.

For example, this defines a function whose ID is computed by the compiler and the function is available as a get-method in TON blockchain explorers:

```func
int get_counter() method_id {
  load_data();
  return ctx_counter;  ;; Some global variable
}
```

This other example defines the same function, but this time it sets the specific ID `65536`. Again, the function is available as a get-method in TON explorers.

```func
int get_counter() method_id(65536) {
  load_data();
  return ctx_counter;  ;; Some global variable
}
```

<Callout type="caution" title="Important limitations and recommendations">
  **19-bit limitation**: Method IDs are limited to signed 19-bit integers, meaning the valid range is from `-2^18` (inclusive) to `(2^18 - 1)` (inclusive),
  i.e., from `-262,144` to `262,143`.

  **Reserved ranges**:

  * -4 to 0 for [special functions](/llms/languages/func/special-functions/content.md): `main` or `recv_internal` (ID = 0), `recv_external` (ID = -1), `run_ticktock` (ID = -2), `split_prepare` (ID = -3), `split_install` (ID = -4)
  * 1 to 999 for additional functions (approximate range).
  * 65536 and above: default range for user functions when using automatic generation: `(crc16(function_name) & 0xffff) | 0x10000`

  **Best practice**: It's recommended to **avoid setting method IDs manually** and rely on automatic generation instead. Manual assignment can lead to conflicts and unexpected behavior.
</Callout>

## Function body [#function-body]

### Empty body [#empty-body]

An empty body, marked with a single semicolon `;` indicates that the function is declared but not yet defined. Its definition must appear later in the same file or a different file processed before the current one by the FunC compiler. A function with an empty body is also called a *function declaration*.

For example:

```func
 int add(int x, int y);
```

This declares a function named `add` with type `(int, int) -> int` but does not define it.

In FunC, all functions must be defined or declared before using them in other functions, which explains the need for function declarations.

For example, the following code calls function `foo` inside the `main` function, but `foo` is defined *after* `main`.

Hence, the compiler rejects the code:

```func
() main() {
  var a = foo();    ;; DOES NOT COMPILE
                    ;; foo is not declared nor
                    ;; defined before main
}

int foo() {
  return 0;
}
```

To fix the error, either declare `foo` before `main`:

```func
int foo();      ;; foo declared before main,
                ;; but defined after main

() main() {
  var a = foo();
}

int foo() {
  return 0;
}
```

Or move the definition of `foo` before main:

```func
int foo() {
  return 0;
}

() main() {
  var a = foo();
}
```

### Assembler body [#assembler-body]

An assembler body defines the function using low-level TVM primitives for use in a FunC program. The body consists on the keyword `asm`, followed a list of TVM instructions, and ending with symbol `;`.

For example:

```func
  int add(int x, int y) asm "ADD";
```

This defines the function `add` of type `(int, int) -> int`, using the TVM instruction `ADD`.

Refer to the [assembler functions](/llms/languages/func/asm-functions/content.md) article for more details.

### Standard body [#standard-body]

A standard body uses a [block statement](/llms/languages/func/statements/content.md), i.e., the body of the function is defined inside curly braces `{ }`.

For example:

```func
int add(int x, int y) {
  return x + y;
}
```

This defines a function that adds its two arguments and returns the result of the addition.

## `forall` declarator [#forall-declarator]

The `forall` declarator has the following syntax:

```func
forall <comma separated list of type variables names> ->
```

The declarator starts with the `forall` keyword and finishes with the symbol `->`. Each element in the comma separated list must be a type variable name. A type variable name can be any [identifier](/llms/languages/func/literals/content.md), but capital letters are commonly used.

The `forall` declarator makes the function a [polymorphic function](https://en.wikipedia.org/wiki/Parametric_polymorphism), meaning that when the function is called, the type variables get replaced with actual types.

For example:

```func
forall X, Y -> [Y, X] pair_swap([X, Y] pair) {
  [X p1, Y p2] = pair;
  return [p2, p1];
}
```

This function declares two type variables `X` and `Y`. The function uses these two type variables to declare an argument `pair` of type `[X, Y]`, i.e., a [tuple](/llms/languages/func/types/content.md) where the first component is of type `X` and the second component of type `Y`. The function then swaps the components of the tuple and returns a tuple of type `[Y, X]`.

That `pair_swap` is polymorphic means that it can be called with tuples of type `[int, int]`, `[int, cell]`, `[cell, slice]`, `[[int, int], cell]`, etc.

For instance:

* `pair_swap([2, 3])` returns `[3, 2]`. In this case, both type variables `X` and `Y` get substituted with `int`.
* `pair_swap([1, [2, 3, 4]])` returns `[[2, 3, 4], 1]`. In this case, type variable `X` gets substituted with `int`, and `Y` with `[int, int, int]`.

Even though the function is polymorphic, the compiled assembly code remains the same for any substitution of the type variables. This is possible due to the polymorphic nature of stack manipulation operations.

However, other forms of polymorphism, such as [`ad-hoc` polymorphism](https://en.wikipedia.org/wiki/Ad_hoc_polymorphism) with type classes, are not supported.

<Callout>
  At the moment, type variables in polymorphic functions cannot be instantiated with tensor types. There is only one exception: the tensor type `(a)`, where `a` is not a tensor type itself, since the compiler treats `(a)` as if it was `a`.

  This means you can't use `pair_swap` on a tuple of type `[(int, int), int]` because type `(int, int)` is a tensor type.
</Callout>
