-
Notifications
You must be signed in to change notification settings - Fork 14
Documentation for Tolk written from scratch #1421
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
- all articles about Tolk type system - get rid of 'you' and 'we' in existing pages
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the solid Tolk docs update; I left several style and wording suggestions in languages/tolk files—please apply the inline suggestions where they make sense.
| For years, FunC was the primary language for TON. | ||
| It gave complete control over the TVM — and if you mastered it, it gave you power. | ||
| But its Lisp-like syntax and functional style made onboarding difficult for many. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[HIGH] Second-person pronoun and hype in FunC origin note
The sentence “It gave complete control over the TVM — and if you mastered it, it gave you power.” addresses the reader with “you” and uses hype-style wording (“gave you power”). This violates the guidelines against personal pronouns and marketing-style language in technical documentation. The surrounding narrative can remain factual while removing the second person and hype.
| For years, FunC was the primary language for TON. | |
| It gave complete control over the TVM — and if you mastered it, it gave you power. | |
| But its Lisp-like syntax and functional style made onboarding difficult for many. | |
| For years, FunC was the primary language for TON. | |
| It provided complete control over the TVM for developers who mastered it. | |
| But its Lisp-like syntax and functional style made onboarding difficult for many. |
Please leave a reaction 👍/👎 to this suggestion to improve future reviews for everyone!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Intentional "you", see the MR description
| obj.toCell({ | ||
| // for `bits128` and similar (a slice under the hood), | ||
| // insert the checks (bits == 128 and refs == 0); | ||
| // turn off to save gas if you guarantee input is valid; | ||
| // `intN` are always validated, it's only for `bitsN` | ||
| skipBitsNValidation: false, // default: false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[HIGH] Second-person pronoun in auto-serialization options comment
The inline comment “// turn off to save gas if you guarantee input is valid;” uses “you” to refer to the reader, even though this is explanatory documentation embedded in a code example. This conflicts with the style rule to avoid second-person pronouns in docs, including explanatory comments used for teaching. The meaning can be preserved by referring to conditions on the input instead.
Please leave a reaction 👍/👎 to this suggestion to improve future reviews for everyone!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Intentional "you", see the MR description
| <Aside | ||
| type="caution" | ||
| > | ||
| This page gives brief descriptions of optimizations performed. | ||
| It is fairly low-level and not required for using Tolk in production. | ||
| </Aside> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[HIGH] Throat-clearing “this page/section” openers
Multiple newly added Tolk pages start sections with self-referential “this page/section” sentences instead of leading directly with value, which the style guide flags as throat-clearing. In features/compiler-optimizations.mdx, the caution aside says “This page gives brief descriptions of optimizations performed. It is fairly low-level and not required for using Tolk in production.”; similar constructions appear in features/message-sending.mdx (“This section is intended for experienced users; it discusses terminology.”), syntax/operators.mdx, syntax/structures-fields.mdx, types/list-of-types.mdx, types/overall-serialization.mdx, and types/overall-tvm-stack.mdx. These meta statements add cognitive overhead without conveying new information. Rephrasing them into direct summaries of purpose, audience, or prerequisites keeps the docs concise and aligned with the style rule.
| <Aside | |
| type="caution" | |
| > | |
| This page gives brief descriptions of optimizations performed. | |
| It is fairly low-level and not required for using Tolk in production. | |
| </Aside> | |
| <Aside | |
| type="caution" | |
| > | |
| Summarizes compiler optimizations that affect gas usage. | |
| Intended as low-level background; not required for typical Tolk development. | |
| </Aside> |
Please leave a reaction 👍/👎 to this suggestion to improve future reviews for everyone!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not the start of the page, it's an <Aside> element after, placed specifically to attract visual attention
| If you use `RichBounce`, that's the way: | ||
|
|
||
| ```tolk | ||
| fun onBouncedMessage(in: InMessageBounced) { | ||
| val rich = lazy RichBounceBody.fromSlice(in.bouncedBody); | ||
| // handle rich.originalBody | ||
| // use rich.xxx to get exitCode, gasUsed, and so on | ||
| } | ||
| ``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[HIGH] Second-person pronoun in RichBounce handling guidance
The line “If you use RichBounce, that's the way:” addresses the reader directly with “you”. This breaks the rule against using “you/your” in documentation and mixes instructional tone with informal phrasing (“that's the way”). The surrounding section already describes BounceMode variants objectively, so this sentence can be made neutral and descriptive.
Please leave a reaction 👍/👎 to this suggestion to improve future reviews for everyone!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Intentional "you", see the MR description
| - sometimes, you "send to an address" | ||
| - ... but sometimes, you have workchain + hash | ||
| - sometimes, you compose `StateInit` from code+data | ||
| - ... but sometimes, `StateInit` is a ready cell | ||
| - sometimes, you send a message to basechain | ||
| - ... but sometimes, you use a `MY_WORKCHAIN` constant | ||
| - sometimes, you just attach tons (msg value) | ||
| - ... but sometimes, you also need extra currencies |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[HIGH] Second-person pronouns in createMessage union examples
The bullet list under “The concept is based on union types” uses multiple second-person constructions such as “sometimes, you 'send to an address'” and “sometimes, you just attach tons (msg value)”. These directly address the reader instead of describing generic behaviors, violating the no-“you/your” rule for documentation text. The list is otherwise explaining patterns of usage and can be written in neutral terms.
| - sometimes, you "send to an address" | |
| - ... but sometimes, you have workchain + hash | |
| - sometimes, you compose `StateInit` from code+data | |
| - ... but sometimes, `StateInit` is a ready cell | |
| - sometimes, you send a message to basechain | |
| - ... but sometimes, you use a `MY_WORKCHAIN` constant | |
| - sometimes, you just attach tons (msg value) | |
| - ... but sometimes, you also need extra currencies |
Please leave a reaction 👍/👎 to this suggestion to improve future reviews for everyone!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Intentional "you", see the MR description
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One more comment about "you" in these intentional places:
Even in strict docs of Rust, LLVM, Oracle, etc. it's also quite typical:
- Sometimes you need…
- Sometimes you have…
- etc.
Like here. What's important:
It does not address the reader, contains no imperatives, and avoids direct dialogue.
It is simply a description of a situation, not an interaction with the user.
| Returns `uint256` — a new pseudo-random number. | ||
|
|
||
| Ensure you've called `random.initialize` to make it unpredictable! | ||
|
|
||
| #### random.range(limit) | ||
|
|
||
| Returns `int` — a new pseudo-random integer z in the range `0..limit−1` (or `limit..−1` if negative). | ||
| More precisely, an unsigned random value `x` is generated, then `z := x * limit / 2^256` is computed. | ||
|
|
||
| Ensure you've called `random.initialize` to make it unpredictable! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[HIGH] Second-person pronouns in random API notes
Within the random.uint256 and random.range documentation, the line “Ensure you've called random.initialize to make it unpredictable!” appears twice. Both instances directly address the reader with “you've”, which conflicts with the style rule against second-person pronouns in documentation prose. The intent—documenting the need to initialize randomness—can be expressed in a neutral imperative form instead.
Please leave a reaction 👍/👎 to this suggestion to improve future reviews for everyone!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Intentional "you", see the MR description
| - Do you need validation or just proxy any data as-is? | ||
| - Do you need custom error codes while validating? | ||
| - Do you need to assign it dynamically or just to carry it forward? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[HIGH] Second-person pronouns in jetton forward-payload questions
Lines 533–535 ask the reader “Do you need …” three times, directly addressing the reader with “you”. This conflicts with the documentation style rule to avoid second-person pronouns in descriptive guidance. The surrounding section is otherwise neutral and technical, so the second-person phrasing stands out as inconsistent with the rest of the Tolk docs.
| - Do you need validation or just proxy any data as-is? | |
| - Do you need custom error codes while validating? | |
| - Do you need to assign it dynamically or just to carry it forward? |
Please leave a reaction 👍/👎 to this suggestion to improve future reviews for everyone!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Intentional "you", see the MR description
| If you are migrating from FunC: | ||
|
|
||
| int currentCounter() method_id { | ||
| load_data(); ;; fills global variables | ||
| return ctx_counter; | ||
| } | ||
| ``` | ||
| </details> | ||
| - Look through [benchmarks](https://github.com/ton-blockchain/tolk-bench): notice **30–50% lower gas fees**. | ||
| - Scan the page [Tolk vs FunC](/languages/tolk/from-func/tolk-vs-func) to get the overall picture. | ||
| - Use the [FunC-to-Tolk converter](/languages/tolk/from-func/converter) to migrate existing projects. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[HIGH] Second-person pronoun in FunC migration note
The line “If you are migrating from FunC:” explicitly addresses the reader with “you”. This violates the style rule banning second-person pronouns in documentation, even though the rest of the migration guidance is written neutrally. The heading line can be rephrased to describe the migration topic without addressing the reader directly.
Please leave a reaction 👍/👎 to this suggestion to improve future reviews for everyone!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Intentional "you", see the MR description
| --- | ||
|
|
||
| An article ["Type checks and casts"](/languages/tolk/types/type-checks-and-casts) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[HIGH] Horizontal rule in type system overview body
Line 33 contains a standalone --- after the list of type links, which renders as a horizontal rule. The style guide permits --- only as YAML frontmatter delimiters, not as thematic breaks in body content. This horizontal rule appears in the middle of the page body (not as frontmatter), so it violates the “no thematic breaks in content” rule.
| --- | |
| An article ["Type checks and casts"](/languages/tolk/types/type-checks-and-casts) | |
| An article ["Type checks and casts"](/languages/tolk/types/type-checks-and-casts) |
Please leave a reaction 👍/👎 to this suggestion to improve future reviews for everyone!
| ## `void` and `never` | ||
|
|
||
| Both represent the absence of a value and occupy zero stack slots. | ||
|
|
||
| For example, a `void` function does not place any value onto the stack. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[HIGH] Horizontal rule in TVM stack overview body
Near the end of overall-tvm-stack.mdx, a standalone --- line is used as a separator before the “See also” section (immediately following this range). As with the type-system overview, this is a thematic break in body content rather than YAML frontmatter. The documentation style guide disallows horizontal rules in page content, so this separator should be removed and replaced by normal spacing or headings.
Please leave a reaction 👍/👎 to this suggestion to improve future reviews for everyone!
| \=> search for "TON" in Marketplace and install | ||
|
|
||
| All contracts in the [Tolk vs FunC benchmarks](https://github.com/ton-blockchain/tolk-bench) pass the same test suites as their FunC counterparts — with identical logic and behavior. | ||
| 1. **Cursor, Windsurf, and other** editors — via the [language server](https://github.com/ton-blockchain/ton-language-server)<br /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LS is suitable for Neovim, Vim, etc. editors, for Cursor and Windsurf lets add another item with link to Open VSX: https://open-vsx.org/extension/ton-core/vscode-ton
| ```tolk | ||
| import "another-file" | ||
| // symbols from `another-file.tolk` are visible |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This wording is a bit confusing to me, maybe something like symbols from 'another-file.tolk' can be used in the file now
|
|
||
| In typical workflows, an IDE inserts imports automatically (for example, when selecting an element from auto‑completion). | ||
|
|
||
| Note: the entire file is imported, all its symbols are accessible. There are no "modules" or "exports", all symbols must have unique (verbose) names project-wise. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we use :::note ::: here for better visibility?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We use explicit components instead of Markdown directives, :::. The <Aside> component was intentionally made to be Starlight & Astro-compatible*, and it should be used for all asides/callouts :)
* custom icon pack is different and there's no way to choose different packs in Starlight's default Aside
| fun demo() { | ||
| // create an object | ||
| val p1: Point = { x: 10, y: 20 }; | ||
| // the same, type auto-inferred |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a bit confusing what type is automatically inferred, maybe something like the same, type of p2 is auto-inferred
|
|
||
| - methods are declared like `fun Point.method(self)`, read below | ||
| - fields can have any types: numeric, cell, union, etc. (see [type system](/languages/tolk/types/list-of-types)) | ||
| - default values for fields: `x: int8 = 0` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
'default values for fields: x: int8 = 0'
but
'fields can have any types: ...'
'fields can be private and readonly'
for consistency maybe we can write it like fields can have default values: ...
| - fields can have any types: numeric, cell, union, etc. (see [type system](/languages/tolk/types/list-of-types)) | ||
| - default values for fields: `x: int8 = 0` | ||
| - fields can be `private` and `readonly` | ||
| - generic structs are supported: `struct Wrapper<T> { ... }` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Third person style is always difficult to read, maybe something like structs can be generic: ...
|
|
||
| - parameter types are mandatory | ||
| - the return type can be omitted: it will be auto-inferred, like in TypeScript | ||
| - default values supported: `fun f(b: int = 0)` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
parameters can have default value: ...?
|
|
||
| ## Methods | ||
|
|
||
| A function declared `fun <receiver>.name(...)` is a method. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
missed as?
A function declared as fun <receiver>.name(...) is a method.
| ```tolk | ||
| const ONE = 1 | ||
| const MAX_AMOUNT = ton("0.05") | ||
| const ADMIN_ADDRESS = address("EQ...") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe we can add a type hint for one of the constants to show that this is possible?
| } | ||
| ``` | ||
|
|
||
| An interesting example. Imagine a structure which tail is signed: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's add a note that this custom methods will only work with type aliases, not with structs, enums, or unions. I know a few people who find this behavior very surprising and unexpected
|
|
||
| - each incoming message is a struct with an opcode | ||
| - combine these structs into a union | ||
| - parse it via `lazy fromCell` and `match` over variants |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
but in example AllowedMessage.fromSlice(in.body)
| - [cells](/languages/tolk/types/cells) — and also slices, builders, and raw bits | ||
| - [strings](/languages/tolk/types/strings) — not a native type, emulated using slices | ||
| - [structures](/languages/tolk/types/structures) — group several fields into one entity | ||
| - [type aliases](/languages/tolk/types/aliases) — similar to TypeScript and Rust |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't require FunC knowledge, but require TypeScript and Rust knowledge here :D
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
C's typedefs send their regards
| Tolk has several types for integers: | ||
|
|
||
| - general `int` | ||
| - signed `int32`, `int256`, `int88`, etc. (0 \< N ≤ 257) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
N is unclear from the context
| > | ||
| All these types are **257-bit integers at runtime**. | ||
| The TVM (virtual machine) has only `INT`, and all intN are actually "just integers" while running. | ||
| **Overflow happens only at serialization**. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's link with "Overflow happens only at serialization" paragraph bellow
|
|
||
| All numeric types are backed by TVM INT. Serialization happens as follows: | ||
|
|
||
| - `int` — not serialized, use `intN` and other types |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not serializable?
| - `intN` — a fixed N-bit signed integer | ||
| - `uintN` — a fixed N-bit unsigned integer | ||
| - `coins` — alias to `varuint16` | ||
| - `var(u)intN` — variadic N 16/32: 4/5 bits for len + (8\*len)-bit number |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe wrap expression to backticks?
`8*len`
| | Expression | Behavior | | ||
| | :------------------: | :--------------------------------------------: | | ||
| | `condition & f()` | `f()` is called always | | ||
| | `condition && f()` | `f()` is called only if `condition` | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A bit confusing, maybe something like
"f() is called only if condition is true"
| } | ||
| ``` | ||
|
|
||
| Then a cell will be `"FFxxxx".ref(...)`. So "a tail" is because it goes after existing data up to the end. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The name originates from the fact that data occupies all remaining bits in the current cell:
So "a tail" is because it goes after existing data up to the end.
The first one is consfusing because in the example we don't use all 1023 bits, maybe it should be removed and the second one should be left as a clearer explanation
|
|
||
| Read [Functions and methods](/languages/tolk/syntax/functions-methods). | ||
|
|
||
| ## Prefixes do not affect typing or layout |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prefixes have not been introduced and their effects are already described, maybe we need to add a separate paragraph for them
| ## Syntax of structures | ||
|
|
||
| - Shorthand syntax `{ x, y }` is available | ||
| - Default values for fields |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"Default values for fields: a: int32 = 10"
| } | ||
| ``` | ||
|
|
||
| Such a struct has overhead over plain `int32`, but it becomes a distinct type with its own methods and semantics. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't such a structure essentially just an int32 (int) at runtime? What's the overhead?
| } | ||
| ``` | ||
|
|
||
| It reminds `intN` types: `int32` is assignable to `int` and back, `int64` also, but assigning `int32` to `int64` is something strange. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we should describe explicit casting with unsafe as?
|
|
||
| ## Type aliases are extremely useful with unions | ||
|
|
||
| This is a recommended pattern for handling incoming messages: declare a struct for each message, declare a union, parse input into this union, and match over variants: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure, but what's described here doesn't have any intersection with type aliases, does it?
|
|
||
| ## Default type arguments | ||
|
|
||
| At declaration, not only `<T>`, but `<T = xxx>` is allowed. Such type arguments may be omitted at use sites. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Type parameter can have a default type: <T = xxx>. Such type parameters may be omitted at use sites.
| - `Color.Blue as int` evaluates to `2` | ||
| - `2 as Color` evaluates to `Color.Blue` | ||
|
|
||
| Using unsafe `as` can produce invalid enum values (e.g., `100 as Color`). Then operator `==` will return false, and exhaustive `match` will throw 5 (integer out of range). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let's use something like
:::warn
:::
or so, to highlight this section
| Every enum is backed by TVM INT. Serialized as `(u)intN` where `N` is: | ||
|
|
||
| - specified manually: `enum Role: int8 { ... }` | ||
| - or calculated automatically to fit all values |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think these two points deserve a more detailed explanation, as it can be confusing for beginners right now
| A check for `value == null` is required before: | ||
|
|
||
| ```tolk | ||
| if (value != null) { // value is `int` inside |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A check for
value == null
if (value != null) {
maybe it's better to write: A check for value != null
| while (lastCell != null) { | ||
| lastCell = lastCell.beginParse().loadMaybeRef(); | ||
| } | ||
| // here lastCell is 100% null |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what is 90% null? :D
// here lastCell is definitely null
| // idx is `int` | ||
| ``` | ||
|
|
||
| When a variable is 100% null, its type becomes `null`, meaning it can be safely passed to any nullable type: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here
| fun doSmth(c: cell) {} | ||
| fun analyzeStorage(nCells: int, lastCell: cell?) { | ||
| if (nCells) { // then lastCell 100% not null |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe if (nCells > 0) {?
| Tolk supports union types `T1 | T2 | ...` similar to TypeScript. | ||
| They allow a value to belong to one of several possible types. | ||
| Pattern matching over unions is essential for message handling. | ||
| A special case `T | null` is written as `T?` and called "nullable". |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Link to nullable page?
| fun handle(m: IncomingMsg) { | ||
| match (m) { | ||
| Increment => { /* smart cast to Increment */ } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure if smart cast term is common knowledge, maybe // here m is Increment?
| ## Operators `is` and `!is` | ||
|
|
||
| Besides `match`, unions can also be tested using `is`. | ||
| This generalizes `== null`; smart casts also apply: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This generalizes
== null;
I find this part confusing, it adds more questions than answers
|
|
||
| Unions have a complex stack layout, commonly named as "tagged unions". Enums in Rust work the same way. | ||
|
|
||
| Serialization depends on whether `T_i` is a structure with a manual serialization prefix: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
... on whether
i-th type in the union is a structure with ...
| type="caution" | ||
| > | ||
| In most languages, `(v1, v2, ...)` is called a tuple. | ||
| However, in TON, a "tuple" refers to a specific TVM primitive. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Link to tuple article?
| var (i, j) = tensor; | ||
| // more complex example | ||
| var (slice, (i, j)) = ("abcd", (10, 20)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| ``` | ||
|
|
||
| The method `set()` does not create new elements; it only updates existing ones. | ||
| If `idx` is out of bounds in `get()` or `set()`, an exception is thrown. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe specify exact exit code?
| All major IDEs support syntax highlighting and code completion: | ||
|
|
||
| The Tolk compiler itself lives in the `ton` [repository](https://github.com/ton-blockchain/ton). | ||
| 1. **JetBrains IDEs** (WebStorm, CLion, etc.) — via the [plugin](https://github.com/ton-blockchain/intellij-ton)<br /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are dedicated pages for the JetBrains plugin and VSCode/VSCodium extensions:
Marketplace links, installation steps, and features are nicely described there :)
| // modify | ||
| t.1 = 123; | ||
| t.2.storeInt(v.0, 16); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
t instead of v?
t.2.storeInt(t.0, 16);
| var m = createEmptyMap<int8, int32>(); | ||
| ``` | ||
|
|
||
| Of course, maps may be used inside structures: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we really need this Of course,?
|
|
||
| ## Add values to a map | ||
|
|
||
| Use `m.set(k, v)`, `m.delete(k)`, and other suggested methods (a full list is available below): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add values to a map
m.delete(k),
:D
|
|
||
| ## How to emulate `Set<T>` with maps | ||
|
|
||
| A suggestion is to use an "empty tensor" for a map: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just Use an "empty tensor" for a map:
|
|
||
| It will work, a bit noisy. | ||
| Lots of methods for maps are just inapplicable to sets, so its "public interface" is wrong. | ||
| Sets have a much simpler API, literally 4 functions. A canonical suggestion is something like this: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A canonical suggestion is something like this:
to
It's better to create a simple wrapper aroundmap<T, ()>, like this:
| // etc. | ||
| ``` | ||
|
|
||
| ## Low-level: why "isFound" but not "optional value"? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While this section is generally interesting, I think it's too low-level for any smart contract developer. Maybe these details deserve a separate article/chapter?
| // field `b` may be omitted | ||
| val v: WithVoid = { a: 10, c: "" }; | ||
| } | ||
| ``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This example is very confusing, because why would you need to define a field that doesn't exist at all? I think we need an example with <T = void>.
|
|
||
| <TolkHighlight /> | ||
|
|
||
| **FunC** is the first language for writing smart contracts in TON. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FunC is the first high-level language for writing smart contracts in TON.
| TVM is a stack machine, imposing architectural and runtime restrictions. | ||
|
|
||
| Both languages **have IDE plugins**, although support for Tolk is way better. | ||
| JetBrains IDEs, VS Code, and LSP-based editors: Cursor, Windsurf, etc. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
JetBrains IDEs, VS Code, Cursor, Windsurf, and LSP-based editors: Neovim, Zed etc.

Live demo: https://companyname-a7d5b98e-tolk-docs.mintlify.app/languages/tolk/overview
I have completed a long effort to provide a from-scratch documentation for Tolk.
The previous version, which I had been incrementally maintaining since January, focused on "Tolk vs FunC" differences.
The new one does not require any prior knowledge of FunC. A reader approaches Tolk directly.
The documentation contains many examples, snippets, and real-world cases. Before starting this work, I reviewed the official docs for Rust, Go, and Kotlin — to absorb best practices for presenting a programming language.
What's inside: brief description
Every aspect of the Tolk language is covered:
Additionally, there are two entry-point pages:
The english style used while writing
All pages are written in a short, formal style (as opposed to the PR descriptions I like to create).
Syntax highlighting!
The current documentation lacks of syntax highlighing, because Mintlify does not support custom languages. FunC, Fift, etc. — all of them are rendered as black plain text.
Tolk documentation contains hundreds of snippets and looks too depressive without highlithing.
That's why I implemented a temporary solution — all snippets are now colorful, in both dark and light modes. Just take a look:
All ```tolk snippets are highlighted automatically: no changes in
mdxmarkup is required.The highlighing is client-side, via Prism.js, whose sources are embedded. See
snippets/tolk-highlight.jsx. This component is injected into every/languages/tolk/page.Hopefully, some day, Mintlify will introduce native server-side highlighing. Then, we can discuss across coloring. I fine-tuned grammar and palette the way I prefer it (for example, structures and variables have different colors, because of the capital letter). The current VS Code
tmLanguagefile is not suitable for this — it must be updated.For reviewers
If anyone decides to review all the text in this PR, keep this in mind:
...three dots in code snippets are intentional; small snippets are not meant to be copy-pasted — they demonstrate a specific featureAbout merging this PR
Git history is split into multiple sensible commits. For instance, a syntax highlighter is a separate commit.
It's up to you whether to "Squash and merge" all changes into a single commit or to "Rebase and merge" to preserve Git history. I do not see any disadvantages in having multiple commits.
For future changes
If anyone plans to modify the contents in the Tolk documentation, please remember:
The documentation in numbers
All together, the new Tolk documentation contains:
I invested ~200 hours developing the text and picking every word — exactly 14 days, about 14 hours a day.
I hope that, cumulatively, this documentation will save noticeably more time for all TON developers.
Closes #1136
Closes #1120
Closes #1114
Closes #73
Closes #1128
Live demo: https://companyname-a7d5b98e-tolk-docs.mintlify.app/languages/tolk/overview