Skip to content

Conversation

jeshecdom
Copy link
Contributor

@jeshecdom jeshecdom commented Oct 7, 2025

Some links are missing. Needs one last revision.

This comment was marked as outdated.

@novusnota
Copy link
Member

novusnota commented Oct 7, 2025

(maybe I will copy info from Tact docs regarding asm functions).

very nice

latest source: https://raw.githubusercontent.com/tact-lang/tact/refs/heads/main/docs/src/content/docs/book/assembly-functions.mdx

import { Aside } from '/snippets/aside.jsx';

<Aside type="danger">
Needs extensive revamp. Maybe use Tact docs as guidance.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't put TODO in code

```func
int inc_then_negate(int x) asm "INC" "NEGATE";
```
– a function that increments an integer and then negates it. Calls to this function will be translated to 2 assembler commands `INC` and `NEGATE`. An alternative way to define the function is:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplicate to

the following function increments an integer and then negates it:

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An alternative way to define the function is:

There is no code after this sentence.

- `<function_name>` is the function identifier.
- `<comma_separated_function_args>` is a comma separated list of function arguments, each argument declaring a type and an identifier.
- `<specifiers>` are specifiers that instruct the compiler on how to process the function.
- `<function_body>` is the actual function body, which can be of three kinds: a function declaration (i.e., no body), an assembler function, or a standard function body definition.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"For example:" and several examples of such a declaration

It is important to note that `X` and `Y` must each have a type width of 1, meaning they should fit within a single stack entry. This means you can't use `pair_swap` on a tuple like `[(int, int), int]` because type `(int, int)` has a width of 2, taking up two stack entries instead of one.


## Return type
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Return type is probably used a bit more than forall :)

Please put it above that section

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that at the end I decided to move forall to the end of the article.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea :)

}
```
This is a valid definition of the function `pyth`, which has the inferred type `(int, int) (int, int, int)`.
This is a valid definition of the function `pyth`, which has the inferred type `(int, int) -> (int, int, int)`.
Copy link
Collaborator

@verytactical verytactical Oct 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is, but pythagorean triples are probably not very much used in smart contracts.

An example of gas calculation or divmod would be more fitting.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, I had that thought when I read the example.... but left it there. I'll change it.

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.
#### Receive internal
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's not a section about a special function name per se, but about that special function in general.

Probably this should go into a separate section/article about entry points.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean that I should just list the names of the special functions, and then point to a separate article explaining the special functions handling TVM events?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, exactly that

```

#### `inline_ref` specifier
### `inline_ref` specifier
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This section could use a little bit more clarity on how exactly this is implemented. Probably, add an example with the code that uses inline_ref function twice, and how exactly it's stored in BoC.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will need to ask about this one. I actually do not understand fully what it is doing.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So from bitcode point of view there are several options to refer to a function (i.e. continuation, represented as some DAG of cells):

  • Link it into a function dictionary. Now function calls look up the dictionary by function id and run whatever they found there.
  • Link the root cell of function directly to the instruction that calls it. Due to cell deduplication during BoC serialization, all the call sites referring to the same root cell will actually link to the same node in a cell DAG. I think this is inline_ref.
  • Code of function might be very small, only a single cell, but we'll still have to open the cell and pay for it. So instead of referring to the root cell of a function, we glue bits of that root cell directly into the cell that calls it, and use another asm instruction that runs the continuation from bits (instead of ref). This is likely inline.

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`
### `method_id`
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The explanation probably would take a whole section of documentation: we have to explain what a method dictionary is, and how incoming messages use message id to find their handler.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

avoid setting method IDs manually

Should also mention a very common case when it's needed: when method id is set by TEP and doesn't match a generated id.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, I will ask about this.

## Function body

## Assembler function body definition
### Function declaration
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should probably mention why do we need them.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, agreed.

This comment was marked as outdated.

This comment was marked as resolved.

Copy link

Thanks for the updates across the FunC docs. A few high‑severity link and example issues need fixes before merge.

Findings (5)

High (5)

[HIGH] Broken anchor to Expressions section

Location:

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.

Description:
The link expressions#and-in-function-names does not exist in language/func/expressions.mdx. The correct target is the “Special function call notation” section. Internal anchors must resolve to valid sections.

Suggestion:

- Specifically, refer to this [section](expressions#and-in-function-names) to understand how the symbols `.` or `~` affect the function name.
+ Specifically, refer to [special function call notation](expressions#special-function-call-notation) to understand how the symbols `.` or `~` affect the function name.

[HIGH] Empty/broken Markdown links

Location:

The `recv_internal` function is invoked when a smart contract receives **an inbound [internal message]()**.

Description:
Multiple links use empty targets [](), rendering as broken links. Instances include: L19 (“internal message”), L74 (“DROP”), L100 (“external messages”), L110 (“external messages cannot carry coins”), L116 (“tick and tock transactions”), L135–L136 (“split prepare transaction”, “currently not in use”), and L140–L141 (“split install transaction”, “currently unavailable”). These must be removed or replaced with valid links or inline code per the style guide.

Suggestion:

-... receives **an inbound [internal message]()**.
+... receives **an inbound internal message**.
-  to spend gas by explicitly executing a [DROP]() instruction ...
+  to spend gas by explicitly executing a `DROP` instruction ...
-The `recv_external` function handles **inbound [external messages]()**.
+The `recv_external` function handles **inbound external messages**.
-The only difference is that `msg_value` is always `0`, since [external messages cannot carry coins](), as they are created outside the blockchain.
+The only difference is that `msg_value` is always `0`, since external messages cannot carry coins, as they are created outside the blockchain.
-The `run_ticktock` triggers when [tick and tock transactions]() occur.
+The `run_ticktock` triggers when tick and tock transactions occur.
-The `split_prepare` would trigger when a [split prepare transaction]() occurs. Even though the `split_prepare` name is currently reserved,
-split prepare transactions are [currently not in use]().
+The `split_prepare` would trigger when a split prepare transaction occurs. Even though the `split_prepare` name is currently reserved,
+split prepare transactions are currently not in use.
-The `split_install` would trigger when a [split install transaction]() occurs. Even though the `split_install` name is currently reserved,
-split install transactions are [currently unavailable]().
+The `split_install` would trigger when a split install transaction occurs. Even though the `split_install` name is currently reserved,
+split install transactions are currently unavailable.

[HIGH] Broken anchor to method_id specifier

Location:

FunC (specifically, the Fift assembler) reserves several function names with predefined [IDs](functions#method_id):

Description:
The link to predefined IDs points to functions#method_id, but the actual header is “method_id specifier,” which slugs to method_id-specifier. The current link does not resolve.

Suggestion:

-FunC (specifically, the Fift assembler) reserves several function names with predefined [IDs](functions#method_id):
+FunC (specifically, the Fift assembler) reserves several function names with predefined [IDs](functions#method_id-specifier):

[HIGH] Invalid FunC snippet (duplicate type token)

Location:

() recv_internal(slice in_msg_body, int int msg_value, cell in_msg_cell, int balance)

Description:
The example declares int int msg_value without a comma, which is invalid FunC syntax and undermines the example’s instructional value.

Suggestion:

-   () recv_internal(slice in_msg_body, int int msg_value, cell in_msg_cell, int balance)
+   () recv_internal(slice in_msg_body, int msg_value, cell in_msg_cell, int balance)

[HIGH] Literal ellipses used inside code blocks

Location:

int foo() {...}
(int, int) foo'() {...}
[int, int] foo''() {...}
(int -> int) foo'''() {...}
() foo''''() {...}

Description:
The code sample uses ... inside a FunC code block, which is invalid syntax and discouraged by the style guide. Replace with valid declarations to keep examples accurate.

Suggestion:

 ```func
-int foo() {...}
-(int, int) foo'() {...}
-[int, int] foo''() {...}
-(int -> int) foo'''() {...}
-() foo''''() {...}
+int foo();
+(int, int) foo'();
+[int, int] foo''();
+(int -> int) foo'''();
+() foo''''();

@verytactical verytactical marked this pull request as draft October 10, 2025 15:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants