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

Expressions in FunC combine literals, variables, operators, and function calls to produce a value when evaluated.

An expression in FunC can be:

* A [number literal](/llms/languages/func/literals/content.md)
* An [identifier](/llms/languages/func/literals/content.md)
* A [compile-time builtin](/llms/languages/func/literals/content.md)
* An [operator](/llms/languages/func/operators/content.md)
* A [variable declaration](#variable-declaration)
* A [function call](#function-call)

We focus on variable declarations and function calls, since the other kind of expressions are explained in their respective articles.

As a general rule, all sub-expressions inside an expression are evaluated from left to right,
except in cases where [asm stack rearrangement](/llms/languages/func/asm-functions/content.md) explicitly defines the order.

## Variable declaration [#variable-declaration]

Local variables must be initialized at the time of declaration. Since variable declarations are expressions, the result of evaluating a declaration like:

```func
type iden = expr
```

returns the value produced by `expr`, in addition to defining variable `iden` with value `expr`.

For instance: `(int x = 3) + x;` declares `x` and assigns to it the value `3`. The result of the expression `(int x = 3)` is therefore `3`, which means that `(int x = 3) + x` evaluates to `6`, since `x` has value `3` after the declaration.

Here are further examples of variable declarations, where each line is independent from the other ones. It is possible to use the keyword `var` to let the type checker infer the type, see [typed holes](/llms/languages/func/types/content.md).

```func
int x = 2;
var x = 2;               ;; Equivalent to previous, but with type inference
(int, int) p = (1, 2);
(int, var) p = (1, 2);   ;; Equivalent to previous, but with type inference
[int, var, int] t = [1, 2, 3];
```

In the previous examples, `p` and `t` store the entire tensor and tuple, respectively. But it is possible to deconstruct tensors and tuples and assign each component to different variables. Here are some examples that showcase different ways of deconstructing tensors and tuples:

```func
(int x, int y, int z) = (1, 2, 3);       ;; Assign each tensor component to x, y, and z.
(int, int, int) (x, y, z) = (1, 2, 3);   ;; Equivalent to previous
var (x, y, z) = (1, 2, 3);               ;; Equivalent to previous, but with type inference
(int x = 1, int y = 2, int z = 3);       ;; Assigning each component directly
[int x, int y, int z] = [1, 2, 3];       ;; Assign each tuple component to x, y, and z
[int, int, int] [x, y, z] = [1, 2, 3];   ;; Equivalent to previous
var [x, y, z] = [1, 2, 3];               ;; Equivalent to previous, but with type inference
```

A variable can be redeclared in the same scope. For example, the following code is valid:

```func
int x = 2;
int y = x + 1;
int x = 3;
```

In this example, the second occurrence of `int x` is not a new declaration but a compile-time check ensuring that `x` has type `int`. The third line is equivalent to `x = 3;`.

The following example, which redeclares `x` with type `(int, int)` at the third line, is also valid:

```func
int x = 2;
int y = x + 1;
(int, int) x = (y, y + 1);
```

After the third line, variable `x` has type `(int, int)`.

### Variable redeclaration in nested scopes [#variable-redeclaration-in-nested-scopes]

In nested scopes, a new variable with the same name can be declared, just like in C:

```func
int x = 0;
int i = 0;
while (i < 10) {
  (int, int) x = (i, i + 1);
  ;; Here x is a variable of type (int, int)
  i += 1;
}
;; Here, x refers to the original variable of type int declared above
```

However, global variables **cannot** be redeclared. See [Global variables](/llms/languages/func/global-variables/content.md).

### Underscore [#underscore]

The underscore `_` is used when a value is not needed.
For example, if `foo` is a function of type `int -> (int, int, int)`,
you can retrieve only the first return value while ignoring the rest:

```func
(int fst, _, _) = foo(42);
```

## Function call [#function-call]

A function call in FunC follows a conventional syntax: the function name is followed by its arguments, separated by commas. However, unlike many conventional languages, FunC also treats functions as taking a single tensor argument.

For example, suppose `foo` is a function of type `(int, int, int) -> int`. The following two lines are equivalent ways of calling `foo`:

```func
int x = foo(1, 2, 3);    ;; Three arguments separated by ,
int x = foo((1, 2, 3));  ;; The tensor (1, 2, 3) passed as a single argument
```

Equivalently, we could also assign tensor `(1, 2, 3)` to a variable, and then call `foo`:

```func
(int, int, int) t = (1, 2, 3);
int x = foo(t);    ;; Pass the tensor as a single argument
```

### Function composition [#function-composition]

To illustrate how function composition works in FunC, suppose that together with the previous `foo` function, there is also a `bar` function of type `int -> (int, int, int)`.

Since `foo` expects a single tensor argument, you can pass the entire result of `bar(42)` directly into `foo`:

```func
int x = foo(bar(42));
```

This is equivalent to the longer form, which decomposes the result tensor of `bar(42)` and then calls `foo` by passing all arguments separated by commas:

```func
(int a, int b, int c) = bar(42);
int x = foo(a, b, c);
```

### Functions as first-class objects [#functions-as-first-class-objects]

In FunC, functions are first-class objects: they can be assigned to variables, passed as arguments to other functions, and returned from functions.

For example, the following function `apply`, receives a function `f` of type `int -> int`, and a value `v` of type `int` as arguments. Function `apply` invokes `f` with argument `v` and returns the result of the application, i.e., `apply` computes the expression `f(v)`.

```func
int apply(int -> int f, int v) {
  return f(v);
}
```

Let us suppose we have an increment function:

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

We can then invoke `apply` by passing the increment function:

```func
apply(inc, 2);   ;; produces 3, or equivalently, inc(2)
```

It is also possible to assign the increment function to variables:

```func
var f = inc;
```

or return it from functions:

```func
int -> int return_inc() {
  return inc;
}
```

<Callout>
  FunC does not support lambda expressions. This means that it is not possible to create [anonymous functions](https://en.wikipedia.org/wiki/Anonymous_function).
</Callout>

### Special function call notation [#special-function-call-notation]

In addition to the standard syntax for calling a function, FunC supports two function call notations for specific situations, the [non-modifying notation](#non-modifying-notation), and the [modifying notation](#modifying-notation), which are explained next.

#### Non-modifying notation [#non-modifying-notation]

In FunC, a function with at least one argument can be called using the dot `.` notation, also called *non-modifying notation*.

For example, the function `store_uint`, which stores an unsigned integer into a cell builder and returns the modified builder, has type `(builder, int, int) -> builder`, where:

* The first argument is the builder object.
* The second argument is the value to store.
* The third argument is the unsigned integer bit length.

The following way of calling `store_uint`:

```func
builder b = begin_cell();
b = store_uint(b, 239, 8);
```

is equivalent to:

```func
builder b = begin_cell();
b = b.store_uint(239, 8);   ;; Uses non-modifying notation
```

The dot `.` notation allows the first argument of a function to be placed before the function name,
simplifying the code further:

```func
builder b = begin_cell().store_uint(239, 8);
```

which is equivalent to the standard syntax for calling a function:

```func
builder b = store_uint(begin_cell(), 239, 8);
```

Using the `.` notation it is possible to chain many function calls together:

```func
builder b = begin_cell().store_uint(239, 8)
                        .store_int(-1, 16)
                        .store_uint(0xff, 10);
```

which is equivalent to the longer form:

```func
builder b = begin_cell();
b = b.store_uint(239, 8);
b = b.store_int(-1, 16);
b = b.store_uint(0xff, 10);
```

or to the more difficult to read form, which nests all the calls:

```func
builder b = store_uint(
    store_int(
        store_uint(
             begin_cell(),
             239,
             8),
        -1,
        16),
    0xff,
    10
);
```

#### Modifying notation [#modifying-notation]

If a function's first argument is of type `A` and its return type follows the structure `(A, B)`, where `B` is an arbitrary type, the function can be called using the `~` notation, also called *modifying notation*.

The primary purpose of the `~` notation is to automatically update the first argument in a function call. More concretely, suppose `foo` is a function of type `(builder, int, int) -> (builder, int)`, then the call `v = b~foo(2, 3)`, which uses the `~` notation, is equivalent to the standard call `(b, v) = foo(b, 2, 3)`. The statement `(b, v) = foo(b, 2, 3)` reassigns (or updates) the first argument `b` after the call to `foo` finishes. The `~` notation serves as a shortcut to express this reassignment of the first argument.

One possible application of the `~` notation is for working with cell slices. For example, consider a cell slice `cs` and the function `load_uint`, which has type: `(slice, int) -> (slice, int)`. The function `load_uint` takes a cell slice and a number of bits to load, returning the remaining slice and the loaded unsigned integer value.

The following three calls are equivalent:

```func
(cs, int x) = load_uint(cs, 8);     ;; Standard function call
(cs, int x) = cs.load_uint(8);      ;; Call using non-modifying notation (i.e., `.`)
int x = cs~load_uint(8);            ;; Call using modifying notation (i.e., `~`)
```

#### Adapting functions to use `~` [#adapting-functions-to-use-]

When a function type is of the form `(A, ...) -> A`, it is possible to adapt the function so that the `~` notation can be used on such a function. This can be achieved using unit types, by redefining the function type to `(A, ...) -> (A, ())`.

For example, consider an increment function `inc` of type `int -> int`:

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

To increment a variable `y` using `inc`, the function should be used as follows:

```func
y = inc(y);
```

Attempting to use the `~` notation on `inc` would fail:

```func
y~inc();    ;; DOES NOT COMPILE
```

because `inc` does not have a return type of the form `(int, B)`, where `B` is some type.

To use the `~` notation on `inc`, first redefine the function so that it now has type `int -> (int, ())` as follows:

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

Now, the following code increments `y`:

```func
y~inc();
```

#### `.` and `~` in function names [#-and--in-function-names]

Previously, we redefined `inc` to have type `int -> (int, ())` so that it was possible to use the `~` notation on it.

However, it would be bothersome to use `inc` in cases where we do not want to increment a variable, but we just want to store the increment in a different variable:

```func
(int y, _) = inc(x);
```

In other words, we would *also* like to use `inc` as if it was the original function with type `int -> int`:

```func
int y = inc(x);
```

In FunC, it is possible to *also* keep the original `inc` of type `int -> int` so that we can use `inc` in different ways, like:

```func
x~inc(); ;; Increments x, using modifying notation
int y = inc(x); ;; Doesn't modify x, but stores the increment in y
int z = x.inc(); ;; Equivalent to previous, but using non-modifying notation
```

This is achieved by declaring a function `~inc` alongside the original `inc`:

```func
int inc(int x) {    ;; Original inc function
  return x + 1;
}
(int, ()) ~inc(int x) {  ;; inc version to be able to use ~ notation
  return (x + 1, ());
}
```

This is possible because of the way FunC resolves function calls:

* If a function is called with `.`, e.g., `x.foo()`, the compiler looks for a `.foo` definition.
* If a function is called with `~`, e.g., `x~foo()`, the compiler looks for a `~foo` definition.
* If neither `.foo` nor `~foo` is defined, the compiler falls back to the regular `foo` definition.
