Skip to main content
FunC is the first high-level language for writing smart contracts in TON. For years, it was the only option. Lots of production code was written in FunC, and it will always be alive on-chain and in developers’ hearts. Tolk replaces FunC with modern syntax, a robust type system, and built-in serialization — while generating efficient assembly code. Released in 2025, now it is considered the primary language for the TON ecosystem.

How to migrate from FunC to Tolk

  1. Scan the list below to get the overall picture.
  2. Explore the tolk-bench repo as a source of reference contracts.
  3. 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, 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 (“FunC” stands for “functional C”)
  • Tolk: resembles TypeScript, Rust, and Kotlin
See: basic syntax.

Tolk has structures

  • FunC: return long unnamed tensors such as (int, slice, int, int)
  • Tolk: declare a struct, it’s the same efficient
See: structures.

Automatic serialization

  • FunC: manual bit-level work with builders and slices
  • Tolk: declare a struct and call fromCell and toCell
Pay attention to the use of 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 lazy keyword loads only requested fields skipping the rest
See: lazy loading.

The bool type

  • FunC: only integers, ‘true’ is -1, ‘false’ is 0; ifnot
  • Tolk: type bool and logical operators && || ! are supported
See: booleans.

The address type

  • FunC: only slices (binary data); parse and compare bits
  • Tolk: type address with convenient methods and operator ==
See: address.

Null safety

  • FunC: any variable can hold null, which may lead to runtime errors
  • Tolk: provides nullable types T?, null safety, and smart casts
See: nullability.

Everything else in the type system

  • FunC: several types exposing TVM primitives
  • Tolk: a wide range of types, including unions, generics, and enums
See: type system overview.

Methods for any types

  • FunC: global-scope functions only
  • Tolk: both functions and methods — for structures and even primitives
See: functions and methods.

No impure keyword

  • FunC: once impure is forgotten, a call may be dropped
  • Tolk: the compiler does not remove user function calls

No ~tilde methods

  • FunC: x~f() and x.f() are different (mutating and not)
  • Tolk: only the dot — a single, consistent way to call methods
See: mutability.

Native maps over TVM dictionaries

  • FunC: m~idict_set_builder(1,32,begin_cell().store_uint(10,32))
  • Tolk: m.set(1, 10)
See: maps.

Modern message handling

  • FunC: () recv_internal(4 params) and parse a message cell
  • Tolk: fun onInternalMessage(in) and use in.senderAddress, etc.
See: message handling.

No if (op == OP_TRANSFER) for opcodes

  • FunC: if-else to route an incoming message based on opcode
  • Tolk: use union types and pattern matching
See: pattern matching.

No “ignore empty messages” pattern

  • FunC: recv_internal() starts with if (slice_empty?(...))
  • Tolk: just use else in match
See: lazy matching.

Native message composition

  • FunC: store_uint(0, 1 + 4 + 4 + 64 + 32 + 1 + 1) etc.
  • Tolk: createMessage that auto-detects body ref or not
See: message sending.

Native deployment and StateInit

  • FunC: manually pack contract’s code and data according to TL-B
  • Tolk: createMessage auto-computes destination
See: message sending.

op::increase is not a valid identifier

  • FunC: allows any symbols in identifiers, even var 2+2 = ... is ok
  • Tolk: alphanumeric identifiers, 2+2 is 4, as expected
See: variables.

Small functions are inlined automatically

  • FunC: prefer larger functions for reduced gas consumption
  • Tolk: the compiler auto-inlines functions with zero overhead
is reduced to “return 2” in assembler:
Note: 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
is translated to just
See: compiler optimizations.

Standard library redesigned

Functions from stdlib.fc now use longer, descriptive naming: Many global-scope functions became methods for primitives: String postfixes like "..."c became built-in functions: See: differences in a standard library.

… and of course — assembler functions

Regardless of being a high-level language, Tolk provides all low-level capabilities. The code can still be written in a “FunC-style” with manual builders and slices, exotic TVM instructions can still be used.
See: assembler functions.