diff --git a/docs.json b/docs.json
index d89495e5..43952a3e 100644
--- a/docs.json
+++ b/docs.json
@@ -397,9 +397,18 @@
"language/func/operators",
"language/func/expressions",
"language/func/statements",
- "language/func/functions",
- "language/func/global-variables",
- "language/func/compiler-directives",
+ {
+ "group": "Program declarations",
+ "expanded": true,
+ "pages": [
+ "language/func/declarations-overview",
+ "language/func/functions",
+ "language/func/special-functions",
+ "language/func/asm-functions",
+ "language/func/global-variables",
+ "language/func/compiler-directives"
+ ]
+ },
"language/func/built-ins",
"language/func/dictionaries"
]
diff --git a/language/func/asm-functions.mdx b/language/func/asm-functions.mdx
new file mode 100644
index 00000000..0979a81f
--- /dev/null
+++ b/language/func/asm-functions.mdx
@@ -0,0 +1,200 @@
+---
+title: "Assembler functions"
+sidebarTitle: "Assembler functions"
+noindex: "true"
+---
+
+import { Aside } from '/snippets/aside.jsx';
+
+## Assembler function definition
+
+In FunC, functions can be defined directly using assembler code. This is done by declaring the function body using the `asm` keyword,
+followed by one or more assembler commands written inside double quotes `"`, and finalizing with the symbol `;`.
+For example, the following function increments an integer and then negates it:
+
+```func
+int inc_then_negate(int x) asm "INC" "NEGATE";
+```
+
+Calls to `inc_then_negate` are translated to 2 assembler commands `INC` and `NEGATE`.
+
+Alternatively, the function can be written as:
+
+```func
+int inc_then_negate'(int x) asm "INC NEGATE";
+```
+
+Here, `INC NEGATE` is treated as a single assembler command by FunC, but the Fift assembler correctly interprets it as two separate commands.
+
+
+
+### Multi-line asms
+
+Multi-line assembler commands, including Fift code snippets, can be defined using triple-quoted strings `"""`.
+For instance:
+
+```func
+slice hello_world() asm """
+ "Hello"
+ " "
+ "World"
+ $+ $+ $>s
+ PUSHSLICE
+""";
+```
+
+## Stack calling conventions
+
+The syntax for arguments and returns is the same as for standard functions, but there is one caveat - argument values are pushed onto the
+stack before the function body is executed, and the return type is what is captured from the stack afterward.
+
+### Arguments
+
+When calling an asm function, the first argument is pushed onto the stack first, the second one second, and so on,
+so that the first argument is at the bottom of the stack and the last one at the top.
+
+```func
+builder storeCoins(builder b, int value) asm "STVARUINT16";
+ ;; | |
+ ;; | Pushed last, sits on top of the stack
+ ;; |
+ ;; Pushed first, sits at the bottom of the stack
+
+ ;; The instruction "STVARUINT16" stores
+ ;; integer "value" into builder "b",
+ ;; by taking the builder from the bottom of the stack
+ ;; and the integer from the top of the stack,
+ ;; producing a new builder at the top of the stack.
+```
+
+### Returns
+
+An assembler function's return type attempts to grab relevant values from the resulting stack after the function execution
+and any [result rearrangements](#rearranging-stack-entries).
+
+Specifying an [atomic type](./types#atomic-types), such as an `int`, `cell`, or `builder`, will make the assembler function
+capture the top value from the stack.
+
+For example, in the function,
+
+```func
+builder storeCoins(builder b, int value) asm "STVARUINT16";
+```
+
+the instruction `STVARUINT16` produces a final builder at the top of the stack, which is returned by the `storeCoins` function.
+
+Specifying a [tensor type](./types#tensor-types) as a return type, such as `(int, int)`, will cause the assembler function to take as many elements from the stack as
+the number of components in the tensor type. If the tensor type has nested tensor types, like `((int, int), int)`,
+it is interpreted as if it was the flattened tensor type `(int, int, int)`.
+
+For example, this function duplicates its input, so that if the input is `5`, it returns the tensor `(5, 5)`.
+
+```func
+(int, int) duplicate(int a) asm "DUP";
+ ;; DUP reads the value at the top of the stack
+ ;; and pushes a copy.
+ ;; Since the return type is (int, int),
+ ;; the function takes the first two values in the stack
+ ;; and returns them.
+```
+
+# Stack registers
+
+The so-called _stack registers_ are a way of referring to the values at the top of the stack. In total,
+there are 256 stack registers, i.e., values held on the stack at any given time.
+
+Register `s0` is the value at the top of the stack, register `s1` is the value immediately after it, and so on,
+until we reach the bottom of the stack, represented by `s255`, i.e., the 256th stack register.
+When a value `x` is pushed onto the stack, it becomes the new `s0`. At the same time, the old `s0` becomes the new `s1`, the old `s1` becomes the new `s2`, and so on.
+
+```tact
+int takeSecond(int a, int b) {
+ ;; ↑ ↑
+ ;; | Pushed last, sits on top of the stack
+ ;; Pushed first, sits second from the top of the stack
+
+ ;; Now, let's swap s0 (top of the stack) with s1 (second-to-top)
+
+ ;; Before │ After
+ ;; ───────┼───────
+ ;; s0 = b │ s0 = a
+ ;; s1 = a │ s1 = b
+ SWAP
+
+ ;; Then, let's drop the value from the top of the stack
+
+ ;; Before │ After
+ ;; ───────┼───────
+ ;; s0 = a │ s0 = b
+ ;; s1 = b │ s1 is now either some value deeper or just blank
+ DROP
+
+ ;; At the end, we have only one value on the stack, which is b
+ ;; Thus, it is captured by our return type `Int`
+}
+
+fun showcase() {
+ takeSecond(5, 10); // 10, i.e., b
+}
+```
+
+## Rearranging stack entries
+
+
+
+Sometimes, the order in which function arguments are passed may not match the expected order of an assembler command.
+Similarly, the returned values may need to be arranged differently.
+While this can be done manually using stack manipulation primitives, FunC has special syntax to handle this.
+
+Considering arrangements, the evaluation flow of the assembly function can be thought of in these 5 steps:
+
+1. The function takes arguments in the order specified by the parameters.
+1. If an argument arrangement is present, arguments are reordered before being pushed onto the stack.
+1. The function body is executed.
+1. If a result arrangement is present, resulting values are reordered on the stack.
+1. The resulting values are captured (partially or fully) by the return type of the function.
+
+The argument arrangement has the syntax `asm(arg2 arg1)`, where `arg1` and `arg2` are some arguments of the function arranged in the order we want to push them
+onto the stack: `arg1` will be pushed first and placed at the bottom of the stack, while `arg2` will be pushed last and placed at the top of the stack.
+Arrangements are not limited to two arguments and operate on all parameters of the function.
+
+```func
+;; Changing the order of arguments to match the STDICT signature:
+;; `c` will be pushed first and placed at the bottom of the stack,
+;; while `b` will be pushed last and placed at the top of the stack
+builder asmStoreDict(builder b, cell c) asm(c b) "STDICT";
+```
+
+The return arrangement has the syntax `asm(-> 1 0)`, where 1 and 0 represent a
+left-to-right reordering of [stack registers](#stack-registers) `s1` and `s0`, respectively.
+The contents of `s1` will be at the top of the stack, followed by the contents of `s0`.
+Arrangements are not limited to two return values and operate on captured values.
+
+```func
+;; Changing the order of return values of LDVARUINT16 instruction,
+;; since originally it would place the modified Slice on top of the stack
+(slice, int) asmLoadCoins(slice s) asm(-> 1 0) "LDVARUINT16";
+;; ↑ ↑
+;; | Value of the stack register 0,
+;; | which is the topmost value on the stack
+;; Value of the stack register 1,
+;; which is the second-to-top value on the stack
+```
+
+Both argument and return arrangement can be combined together and written as follows: `asm(arg2 arg1 -> 1 0)`.
+
+```func
+;; Changing the order of return values compared to the stack
+;; and switching the order of arguments as well
+(slice, int) asmLoadInt(int len, slice s): asm(s len -> 1 0) "LDIX";
+;; ↑ ↑
+;; | Value of the stack register 0,
+;; | which is the topmost value on the stack
+;; Value of the stack register 1,
+;; which is the second-to-top value on the stack
+```
diff --git a/language/func/declarations-overview.mdx b/language/func/declarations-overview.mdx
new file mode 100644
index 00000000..9584d217
--- /dev/null
+++ b/language/func/declarations-overview.mdx
@@ -0,0 +1,13 @@
+---
+title: "Program declarations"
+sidebarTitle: "Overview"
+noindex: "true"
+---
+
+import { Aside } from '/snippets/aside.jsx';
+
+A FunC program is a list of:
+
+- [Function declarations and definitions](./functions)
+- [Global variable declarations](./global-variables)
+- [Compiler directives](./compiler-directives)
diff --git a/language/func/functions.mdx b/language/func/functions.mdx
index b1075a07..25b7b378 100644
--- a/language/func/functions.mdx
+++ b/language/func/functions.mdx
@@ -6,466 +6,420 @@ noindex: "true"
import { Aside } from '/snippets/aside.jsx';
-A FunC program is a list of function declarations, function definitions, and global variable declarations. This section focuses on function declarations and definitions.
+Every function declaration or definition follows a common pattern. The general form is:
-Every function declaration or definition follows a common pattern, after which one of three elements appears:
+```func
+[] ()
+```
-- 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. For example:
- ```func
- int add(int x, int y);
- ```
- This declares a function named `add` with the type `(int, int) → int` but does not define it.
+where `[ ... ]` represents an optional entry. Here,
-- An assembler function body definition defines the function using low-level TVM primitives for use in a FunC program. For example:
- ```func
- int add(int x, int y) asm "ADD";
- ```
- This defines the function `add` using the TVM opcode `ADD`, keeping its type as `(int, int) → int`.
+- `` is the [`forall` declarator](#forall-declarator), which declares that the function is [polymorphic](https://en.wikipedia.org/wiki/Parametric_polymorphism). This is optional.
+- `` is the [return type](#return-type) of the function.
+- `` is the [function name](#function-name).
+- `` is a comma separated list of [function arguments](#function-arguments), each argument consisting on a type and the argument's name.
+- `` are [specifiers](#specifiers) that instruct the compiler on how to process the function.
+- `` 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).
-- A standard function body uses a block statement, the most common way to define functions. For example:
- ```func
- int add(int x, int y) {
- return x + y;
- }
- ```
- This is a standard definition of the `add` function.
+## Return type
+
+The return type can be any atomic or composite type, as described in the [Types](./types) section. For example, the following functions are valid:
-## Function declaration
-As mentioned earlier, every function declaration or definition follows a common pattern. The general form is:
```func
-[] ()
+int foo() { return 0; }
+(int, int) foo'() { return (0, 0); }
+[int, int] foo''() { return [0, 0]; }
+(() -> int) foo'''() { return foo; }
+() foo''''() { return (); }
```
-where `[ ... ]` represents an optional entry.
-
-### Function name
-A function name can be any valid [identifier](/language/func/literals#identifiers). Additionally, it may start with the symbols `.` or `~`, which have specific meanings explained in the [Statements](/language/func/statements#methods-calls) section.
+FunC also supports **type inference** with the use of underscore `_` as the return type. For example:
-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](/language/func/stdlib).
+```func
+_ divAndMod(int m, int n) {
+ return (m /% n);
+}
+```
-#### Special function names
-FunC (specifically, the Fift assembler) reserves several function names with predefined [IDs](/language/func/functions#method_id):
+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](./operators#division-and-modulo%2C-%2F%25) operator `/%`,
+which always returns a two-element tensor `(int, int)`.
-- `main` and `recv_internal` have `id = 0`
-- `recv_external` has `id = -1`
-- `run_ticktock` has `id = -2`
+## Function name
-Every program must include a function with `id = 0`, meaning it must define either `main` or `recv_internal`.The `run_ticktock` function is used in ticktock transactions of special smart contracts.
+A function name can be any valid [identifier](./literals#identifiers).
+Additionally, it may start with the symbols `.` or `~`, which have specific meanings explained in the [special function call notation](./expressions#special-function-call-notation) section.
+Specifically, refer to this [section](./expressions#and-in-function-names) to understand how the symbols `.` or `~` affect the function name.
-#### Receive internal
+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](./stdlib).
-The `recv_internal` function is invoked when a smart contract receives **an inbound internal message**. When the [TVM initializes](/tvm/initialization), certain variables are automatically placed on the stack. By specifying arguments in `recv_internal`, the smart contract can access some of these values. Any values not explicitly referenced in the function parameters will remain unused at the bottom of the stack.
+FunC reserves several function names. See the [reserved functions](./special-functions) article for more details.
-The following `recv_internal` function declarations are all valid. Functions with fewer parameters consume slightly less gas, as each unused argument results in an additional `DROP` instruction:
+## Function arguments
-```func
+A function can receive zero or more argument declarations, each declaration separated by a comma. The following kinds of argument declarations are allowed:
-() recv_internal(int balance, int msg_value, cell in_msg_cell, slice in_msg) {}
-() recv_internal(int msg_value, cell in_msg_cell, slice in_msg) {}
-() recv_internal(cell in_msg_cell, slice in_msg) {}
-() recv_internal(slice in_msg) {}
-```
+- Ordinary declaration: an argument is declared using **its type** followed by **its name**.
+ Example:
-#### Receive external
-The `recv_external` function handles **inbound external messages**.
+ ```func
+ int foo(int x) {
+ return x + 2;
+ }
+ ```
-### Return type
+ Here, `int x` declares an argument named `x` of type `int` in function `foo`.
-The return type can be any atomic or composite type, as described in the [Types](/language/func/types) section. For example, the following function declarations are valid:
-```func
-int foo();
-(int, int) foo'();
-[int, int] foo''();
-(int → int) foo'''();
-() foo''''();
-```
+ An example that declares multiple arguments:
-FunC also supports **type inference**. For example:
-```func
-_ pyth(int m, int n) {
- return (m * m - n * n, 2 * m * n, m * m + n * n);
-}
-```
-This is a valid definition of the function `pyth`, which has the inferred type `(int, int) → (int, int, int)`.
-It computes Pythagorean triples based on the given input values.
+ ```func
+ int foo(int x, int y) {
+ return x + y;
+ }
+ ```
-### Function arguments
+ An example that declares no arguments:
-In function arguments, commas separate it. The following types of argument declarations are valid:
+ ```func
+ int foo() {
+ return 0;
+ }
-- Ordinary declaration: an argument is declared using **its type** followed by **its name**. Example: `int x` declares an argument named `x` of type `int` in the function declaration: `() foo(int x);`.
+ ```
- Unused argument declaration: only its type needs to be specified. Example:
+
```func
int first(int x, int) {
return x;
}
```
- This is a valid function definition of type `(int, int) → int`.
+ 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`.
-
-**Argument tensor representation**
+ This defines a function `inc` with the inferred type `int -> int`, meaning `x` is automatically recognized as an `int`.
-Even though a function may appear to take multiple arguments, it takes a single [tensor-type](/language/func/types#tensor-types) argument. For more details on this distinction, refer to the [Function application](/language/func/statements#function-application) section.
-However, for convenience, the individual components of this tensor are conventionally referred to as "function arguments."
-
-### Function calls
+
-#### Non-modifying methods
+## Specifiers
-
+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).
-```func
-example(a);
-a.example();
-```
+### `impure` specifier
-A function with at least **one argument**, it can be called a **non-modifying method**. For example, the function `store_uint` has the type `(builder, int, int) → builder`, where:
-- The second argument is the value to store.
-- The third argument is the bit length.
+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.
-The function `begin_cell` creates a new `builder`. The following two code snippets are equivalent:
+For example, the [stdlib.fc](./stdlib) function [`random`](./stdlib#random) changes the internal state of the random number generator:
```func
-builder b = begin_cell();
-b = store_uint(b, 239, 8);
-```
-```func
-builder b = begin_cell();
-b = b.store_uint(239, 8);
+int random() impure asm "RANDU256";
```
-So the first argument of a function can be passed to it being located before the function name, if separated by `.`. The code can be further simplified:
-The function's first argument is passed before the function name, separated by `.`. The syntax can be further condensed into a single statement:
+The `impure` keyword prevents the compiler from removing calls to this function:
```func
-builder b = begin_cell().store_uint(239, 8);
+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.
```
-It is also possible to chain multiple method calls:
-```func
-builder b = begin_cell().store_uint(239, 8)
- .store_int(-1, 16)
- .store_uint(0xff, 10);
-```
+### Inline specifier
-#### Modifying functions
+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.
-
+Since the `add` function is marked with the `inline` specifier, the compiler substitutes `add(a, b)` with `a + b` directly in the code.
-If:
-- The first argument of a function has type `A`.
-- The function's return type is `(A, B)`, where `B` is any arbitrary type.
+For instance, the compiler will replace the following code:
-Then, the function can be called a modifying method.
+```func
+var a = 1;
+var b = 2;
+var n = add(a, b);
+```
-Modifying functions change their first argument. They assign the first component of the returned value to the variable initially passed as the first argument.
-The following calls are equivalent:
+with this code:
```func
-a~example(); ;;Modifying method syntax
-a = example(a); ;;Standard function call
+var a = 1;
+var b = 2;
+var n = a + b;
```
-**Example:** `load_uint`
+### `inline_ref` specifier
-Suppose `cs` is a cell slice, and `load_uint` has type `(slice, int) → (slice, int)`. It means:
-- `load_uint` takes a cell slice and several bits to load.
-- It returns the remaining slice and the loaded value.
+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.
-The following calls are equivalent:
+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)](/ton/tblkch#1-1-1-tvm-cells) 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:
-```func
-(cs, int x) = load_uint(cs, 8); ;; Standard function call
-```
-```func
-(cs, int x) = cs.load_uint(8); ;; Method call syntax
-```
-```func
-int x = cs~load_uint(8); ;; Modifying method syntax
+```text
+Cell 1
+
+instruction 1
+instruction 2
+.....
+call reference A
+.....
+instruction n
+----------------------------------------
+Reference to cell A | Reference to cell B |
```
-**Modifying methods with no return value**
+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.
-Sometimes, a function only modifies its first argument without returning a meaningful value. To enable modifying method syntax, such functions should return a unit type () as the second component.
+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.
-For example, suppose we want to define a function `inc` of type `int → int`, which increments an integer. To use it as a modifying method, we define it as follows:
+More concretely, imagine the following program:
```func
-(int, ()) inc(int x) {
- return (x + 1, ());
+int foo() inline_ref {
+ return 1;
}
-```
-
-Now, the function can be used in modifying method syntax:
-```func
-x~inc(); ;;Equivalent to x = inc(x);
+int main() {
+ return (foo() + foo());
+}
```
-This will increment `x` in place.
-#### `.` and `~` in function names
+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`:
-Suppose we want to use `inc` as a non-modifying method. We can write:
-
-```func
-(int y, _) = inc(x);
-```
+```text
+Cell M
-However, we can also define `inc` as a modifying method:
+call reference to F
+call reference to F
+ADD
+----------------------------------------
+Reference to F |
-```func
-int inc(int x) {
- return x + 1;
-}
-(int, ()) ~inc(int x) {
- return (x + 1, ());
-}
-```
-Now, we can call it in different ways:
-```func
-x~inc(); ;; Modifies x
-int y = inc(x); ;; Doesn't modify x
-int z = x.inc(); ;; Also doesn't modify x
-```
-**How 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.
-### Specifiers
+Cell F
-In FunC, function specifiers modify the behavior of functions. There are three types:
+1 PUSHINT
+```
-1. `impure`
-2. `inline`/ `inline_ref`
-3. `method_id`
+When `call reference to F` executes, the TVM loads the cell for `F` and executes it.
-One, multiple, or none can be used in a function declaration. However, they must appear in a specific order (e.g., `impure` must come before `inline`).
+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.
-#### `impure` specifier
+The only case where `inline` might be preferable is if the function is called just once, because loading cell references costs gas.
-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.
+However, recursive calls to `inline_ref` functions remain impossible, as TVM cells do not support cyclic references.
-For example, in the [stdlib.fc](/language/func/stdlib) function:
+### `method_id` specifier
-```func
-int random() impure asm "RANDU256";
-```
-Here, `RANDU256` changes the internal state of the random number generator. The `impure` keyword prevents the compiler from removing this function call.
+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.
-#### `inline` specifier
+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() & 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.
-A function marked as `inline` is directly substituted into the code wherever it is called.
-Recursive calls are not allowed for inline functions.
+The `method_id` specifier has the variant `method_id()`, which allows you to set a function's ID to a specific number manually.
-**Example**
+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) add(int a, int b) inline {
- return a + b;
+int get_counter() method_id {
+ load_data();
+ return ctx_counter; ;; Some global variable
}
```
-Since the `add` function is marked with the `inline` specifier, the compiler substitutes `add(a, b)` with `a + b` directly in the code, eliminating the function call overhead.
-Another example of using `inline` from [ICO-Minter.fc](https://github.com/ton-blockchain/token-contract/blob/f2253cb0f0e1ae0974d7dc0cef3a62cb6e19f806/ft/jetton-minter-ICO.fc#L16):
+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
-() save_data(int total_supply, slice admin_address, cell content, cell jetton_wallet_code) impure inline {
- set_data(begin_cell()
- .store_coins(total_supply)
- .store_slice(admin_address)
- .store_ref(content)
- .store_ref(jetton_wallet_code)
- .end_cell()
- );
+int get_counter() method_id(65536) {
+ load_data();
+ return ctx_counter; ;; Some global variable
}
```
-#### `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, TVM executes a `CALLREF` command. This works similarly to `inline`, but with a key difference—since the same cell can be reused multiple times without duplication, `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. However, recursive calls to `inline_ref` functions remain impossible, as TVM cells do not support cyclic references.
-
-#### `method_id`
-
-In a TVM program, every function has an internal integer ID that determines how it can be called.
-By default, ordinary functions are assigned sequential numbers starting from `1`, while contract get-methods use `crc16` hashes of their names.
-The `method_id()` specifier allows you to set a function's ID to a specific value manually.
-If no ID is specified, the default is calculated as `(crc16() & 0xffff) | 0x10000`.
-If a function has the `method_id` specifier, it can be invoked by its name as a get-method in lite client or TON explorer.
-
-