How to migrate from FunC to Tolk
- Scan the list below to get the overall picture.
- Explore the tolk-bench repo as a source of reference contracts.
- Use the FunC-to-Tolk converter to migrate existing projects.
Gas benchmarks
The tolk-bench repository compares FunC and Tolk on several TEPs. For every metric measured, gas consumption reduced 30–50%. Primarily it’s a result of the language design.What Tolk and FunC have in common
Both languages target into Fift assembler. Tolk is not “a wrapper” that transpiles to FunC — it has its own semantic and optimization kernel. Both languages work on TVM after being compiled to bytecode. 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. Both languages are available in blueprint and other client-side tooling. Command-line mode is also supported. But all language aspects are completely different — a huge list below.List of “Tolk vs FunC” differences
Tolk and FunC are completely different. It’s even inaccurate to compare them — the difference lies in the design, not in syntax. Nevertheless, let’s try to summarize the details.Tolk reminds TypeScript and Rust
- FunC: resembles C and Lisp (“FunC” stands for “functional C”)
- Tolk: resembles TypeScript, Rust, and Kotlin
Tolk has structures
- FunC: return long unnamed tensors such as
(int, slice, int, int) - Tolk: declare a struct, it’s the same efficient
Automatic serialization
- FunC: manual bit-level work with builders and slices
- Tolk: declare a struct and call
fromCellandtoCell
int8, uint64, coins — all of them are TVM integers (see numbers).
See: automatic serialization.
Lazy loading
- FunC: for optimization, manual juggling with preloads and skips
- Tolk: the
lazykeyword loads only requested fields skipping the rest
The bool type
- FunC: only integers, ‘true’ is
-1, ‘false’ is0;ifnot - Tolk: type
booland logical operators&& || !are supported
The address type
- FunC: only slices (binary data); parse and compare bits
- Tolk: type
addresswith convenient methods and operator==
Null safety
- FunC: any variable can hold
null, which may lead to runtime errors - Tolk: provides nullable types
T?, null safety, and smart casts
Everything else in the type system
- FunC: several types, the Hindley-Milner type system
- Tolk: a wide range of types, including unions, generics, and enums
Methods for any types
- FunC: global-scope functions only
- Tolk: both functions and methods — for structures and even primitives
No impure keyword
- FunC: once
impureis forgotten, a call may be dropped - Tolk: the compiler does not remove user function calls
No ~tilde methods
- FunC:
x~f()andx.f()are different (mutating and not) - Tolk: only the dot — a single, consistent way to call methods
Native maps over TVM dictionaries
- FunC:
m~idict_set_builder(1,32,begin_cell().store_uint(10,32)) - Tolk:
m.set(1, 10)
Modern message handling
- FunC:
() recv_internal(4 params)and parse a message cell - Tolk:
fun onInternalMessage(in)and usein.senderAddress, etc.
No if (op == OP_TRANSFER) for opcodes
- FunC:
if-elseto route an incoming message based onopcode - Tolk: use union types and pattern matching
No “ignore empty messages” pattern
- FunC:
recv_internal()starts withif (slice_empty?(...)) - Tolk: just use
elsein match
Native message composition
- FunC:
store_uint(0, 1 + 4 + 4 + 64 + 32 + 1 + 1)etc. - Tolk:
createMessagethat auto-detects body ref or not
Native deployment and StateInit
- FunC: manually pack contract’s code and data according to TL-B
- Tolk:
createMessageauto-computes destination
op::increase is not a valid identifier
- FunC: allows any symbols in identifiers, even
var 2+2 = ...is ok - Tolk: alphanumeric identifiers,
2+2is4, as expected
Small functions are inlined automatically
- FunC: prefer larger functions for reduced gas consumption
- Tolk: the compiler auto-inlines functions with zero overhead
inline modifier in FunC works at the Fift level, it’s sub-optimal due to extra stack permutations.
In Tolk, inlining works at the compiler level and is combined with constant folding.
See: compiler optimizations.
Consecutive builder.storeUint are merged
- FunC: manually combine constant stores into
b.storeUint(0x18,6) - Tolk: merges
b.storeUint(...).storeUint(...)if constant
Standard library redesigned
Functions fromstdlib.fc now use longer, descriptive naming:
| FunC | Tolk |
|---|---|
cur_lt() | blockchain.logicalTime() |
car(l) | listGetHead(l) |
raw_reserve(coins) | reserveToncoinsOnBalance(coins) |
~dump(x) | debug.print(x) |
| FunC | Tolk |
|---|---|
s.slice_hash() | s.hash() |
equal_slices_bits(a, b) | a.bitsEqual(b) |
t.tuple_len() | t.size() |
t~tpush(triple(x, y, z)) | t.push([x, y, z]) |
"..."c became built-in functions:
| FunC | Tolk |
|---|---|
"..."c | stringCrc32("...") |
"..."H | stringSha256("...") |
"..."h | stringSha256_32("...") |
"..."a | address("...") |
"..."s | stringHexToSlice("...") |
"..."u | stringToBase256("...") |