# FunC statements (https://docs-kyrm16yq7-ton-core-docs.vercel.app/llms/languages/func/statements/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 statements can occur anywhere inside function bodies.

## Expression statements [#expression-statements]

The most common type of statement is the expression statement—an expression followed by `;`.

See the [FunC expressions](/llms/languages/func/expressions/content.md) article for details on the allowed expressions.

## `return` statement [#return-statement]

The `return` statement ends function execution and specifies a value to be returned to the function caller. Any statement after the `return` statement is not executed.

In this example, the `return` statement instructs the function to halt execution and produce `x + 1` as a result.

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

In this example, only the first `return` executes:

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

## Block statement [#block-statement]

A block statement is used to group zero or more statements. The block is delimited by a pair of curly braces `{ ... }`. A block statement also defines a scope, in which variables defined in the block are accessible only in the block or in nested blocks.

For example:

```func
int x = 1;
int y = 2;
{ ;; x and y are accessible in this block.
  int z = x + y;
  {
    ;; x, y, and z are accessible in this block.
    int w = z;    ;; The block declares w,
                  ;; which is only accessible in this block.
  }
  ;; w is no longer accessible here.
  ;; x, y, and z are still accessible here.
}
;; z is no longer accessible here, but x and y are.
```

## Conditional statements [#conditional-statements]

These statements control the flow of the code based on a condition.

### `if...else` statement [#ifelse-statement]

When executing an `if...else` statement, first, the specified condition is evaluated.

If the condition evaluates to an integer different from `0`, see [absence of boolean type](/llms/languages/func/types/content.md), the block after the condition is executed. Otherwise, if the condition evaluates to `0`, the optional `else` block is executed.

If the `else` block is missing, nothing happens, and execution continues further.

Examples:

```func
;; The condition evaluates to -1, so the block executes
if (1 < 10) {
  do_something();
}
```

```func
;; The condition evaluates to 0, so the block does not execute
if (11 < 10) {
  do_something();
}
;; No else is provided. So, execution continues here, after the block.
```

```func
;; The condition evaluates to 0, so the block does not execute
if (11 < 10) {
  do_something();
} else {         ;; else is provided. So, the else block executes.
  handle_else();
}
```

Curly brackets `{}` are required in each block of an `if...else` statement.

For example, the following code will not compile:

```func
if (1 < 10) {
  do_something();
} else if (2 > 1) {   ;; else block must have curly brackets
  do_something2();
}
```

That is because the `else` block must have curly brackets:

```func
if (1 < 10) {
  do_something();
} else {    ;; else block now has curly brackets
  if (2 > 1) {
    do_something2();
  }
}
```

The above example can be written in a simpler form by using the `elseif` keyword, to avoid the need to write several nested curly brackets in the `else` case:

```func
if (1 < 10) {
  do_something();
} elseif (2 > 1) {
  do_something2();
}
```

In general, the `elseif` keyword is useful for stating several alternative cases:

```func
if (cond) {
  do_1();
} elseif (cond2) {
  do_2();
} elseif (cond23) {
  do_3();
} else {
  do_4();
}
```

The alternative cases can also include the `elseifnot` keyword, which allows the inclusion of [`ifnot` statements](#ifnot-else-statement) in the alternatives:

```func
if (cond) {
  do_1();
} elseif (cond2) {  ;; if in else case
  do_2();
} elseifnot (cond23) {  ;; ifnot in else case
  do_3();
} else {
  do_4();
}
```

### `ifnot...else` statement [#ifnotelse-statement]

The `ifnot...else` statement is equivalent to the [`if...else` statement](#if-else-statement) but with the condition negated using the [bitwise `~` operator](/llms/languages/func/operators/content.md).

More specifically:

```func
ifnot (cond) {
  do_something();
} else {
  handle_else();
}
```

is equivalent to:

```func
if (~ cond) {  ;; Standard if..else, with condition negated using ~
  do_something();
} else {
  handle_else();
}
```

In other words, if the condition in the `ifnot` evaluates to `0`, see [absence of boolean type](/llms/languages/func/types/content.md), the block after the condition is executed. Otherwise, if the condition evaluates to an integer different from `0`, the optional `else` block is executed.

If the `else` block is missing, nothing happens, and execution continues further.

Examples:

```func
ifnot (1 > 10) {   ;; The condition evaluates to 0, the block executes
  do_something();
}
```

```func
ifnot (11 > 10) {   ;; The condition evaluates to -1, the block does not execute
  do_something();
}
;; No else is provided. Execution continues here, after the block.
```

```func
ifnot (11 > 10) {   ;; The condition evaluates to -1, the block does not execute
  do_something();
} else {         ;; else is provided. The else block executes.
  handle_else();
}
```

Similarly to the `if...else`, it is possible to use the keyword `elseifnot` to add several alternative cases:

```func
ifnot (cond) {
  do_1();
} elseifnot (cond2) {
  do_2();
} elseifnot (cond23) {
  do_3();
} else {
  do_4();
}
```

The alternative cases can also include the `elseif` keyword, which allows the inclusion of standard [`if` statements](#if-else-statement) in the alternatives:

```func
ifnot (cond) {      ;; ifnot
  do_1();
} elseif (cond2) {  ;; if in else case
  do_2();
} elseifnot (cond23) {  ;; ifnot in else case
  do_3();
} else {
  do_4();
}
```

## Loops [#loops]

FunC supports `repeat`, `while`, and `do { ... } until` loops. The `for` loop is not supported.

### `repeat` loop [#repeat-loop]

The `repeat` loop executes a block of code a specified number of times. The number of repetitions should be given as a positive 32-bit integer in the inclusive range from `1` to `2^31 - 1`, i.e., `2,147,483,647`. If the value is greater, an error with [exit code 5](/llms/tvm/exit-codes/content.md), `Integer out of expected range`, will be thrown.

```func
int x = 1;
repeat(10) { ;; Repeats the block 10 times.
  x *= 2;    ;; Each iteration multiplies x by 2.
}
;; x has value 1024
```

```func
int x = 1;
int y = 10;
repeat(y + 6) {  ;; Repeats the block 16 times.
  x *= 2;        ;; Each iteration multiplies x by 2.
}
;; x has value 65536
```

If the specified number of repetitions is equal to `0` or any negative number in the inclusive range from `-2^256` to `-1`, it is ignored, and the code block is not executed at all.

```func
int x = 1;
repeat(-1) {  ;; Block does not execute.
  x *= 2;
}
;; x has value 1
```

### `while` loop [#while-loop]

The `while` loop continues executing the block of code as long as the given condition evaluates to an integer different from `0`, see [absence of boolean type](/llms/languages/func/types/content.md).

```func
int x = 5;
while (x < 10) {  ;; Executes the block 5 times.
                  ;; Each iteration increases x by 1.
                  ;; The loop stops when x becomes 10.
  x += 1;
}
;; x has value 10
```

### `do...until` loop [#dountil-loop]

The `do...until` loop is a post-test loop that executes the block of code at least once and then continues to execute it until the given condition evaluates to an integer different from `0`, see [absence of boolean type](/llms/languages/func/types/content.md).

```func
int x = 0;
do {      ;; The block always executes at least once
  x += 3;
} until (x % 9 == 0);  ;; Executes the block 3 times.
                       ;; Each iteration increases x by 3.
                       ;; The loop stops when x becomes divisible by 9.
;; x has value 9
```

## `try...catch` statement [#trycatch-statement]

*Available in FunC since v0.4.0*

The `try...catch` statement consists of a `try` block and a `catch` block. The code in the `try` block is executed first, and if it fails, all changes made within the `try` block are rolled back, and the `catch` block is executed instead.

The `catch` block has two arguments, which are local to the `catch` block:

* The exception parameter, which can be of any type. Used to provide extra information about the error.
* The error code, an integer, which identifies the kind of error.

```func
try {
  do_something();
} catch (x, n) {
  ;; x is the exception parameter
  ;; n is the error code
  handle_exception();
}
```

Unlike many other languages, in FunC, all changes are **undone** if an error occurs inside the `try` block. These modifications include updates to local and global variables and changes to [control registers](/llms/foundations/whitepapers/tvm/content.md). For example, `c4` for storage, `c5`for action/messages, `c7` for context, etc.

Any contract storage updates and outgoing messages are also reverted.

However, certain [TVM state components](/llms/foundations/whitepapers/tvm/content.md) are **not** rolled back, such as:

* Codepage settings
* Gas counters

As a result, all gas consumed within the `try` block is still accounted for, and any modifications carried out by operations that change gas limits (e.g., [`accept_message`](/llms/languages/func/stdlib/content.md) or [`set_gas_limit`](/llms/languages/func/stdlib/content.md)) will remain in effect.

In this example:

```func
int x = 0;
try {
  x += 1;     ;; x now has value 1
  throw(100);
} catch (arg, e) {
  ;; x is rolled back to value 0.
  x += 2;
}
;; Here, x has value 2.
```

although `x` is incremented to `1` inside the `try` block, the modification is **rolled back** due to the exception produced by the [`throw`](/llms/languages/func/built-ins/content.md) function. Hence, `x` has value `0` at the moment the `catch` block starts execution. However, the gas consumed inside the `try` block is **not** rolled back when the `catch` block starts execution.

Here is an example which illustrates how to generate and use the exception parameter:

```func
int x = 10;
try {
  throw_arg(-1, 100);    ;; throw an exception with error code 100
                         ;; and exception parameter -1
} catch (arg, e) {
  if (e == 100) {        ;; Handle exceptions with error code 100
     arg.cast_to_int();  ;; Tell the type checker that the
                         ;; exception parameter is an integer
                         ;; arg = -1, e = 100
     x = arg + 1;
  }
}
;; x has value 0
```

In the above example, [`throw_arg(-1, 100)`](/llms/languages/func/built-ins/content.md) produces an exception with error code `100` and exception parameter `-1`. However, since the exception parameter can be of any type, which may vary depending on the exception, FunC cannot determine its type at compile time in the `catch` block.

This requires the developer to manually cast the exception parameter. In the example, casting of the exception parameter is achieved with the [assembler](/llms/languages/func/asm-functions/content.md) and [polymorphic](/llms/languages/func/functions/content.md) function `cast_to_int`, which receives an argument of any type and returns the same argument as an integer by wrapping the [`NOP` (no operation) TVM instruction](/llms/tvm/instructions/content.md):

```func
forall X -> int cast_to_int(X x) asm "NOP";
```
