Перейти к содержанию
Learning Platform
Глоссарий Troubleshooting
Урок 05.06 · 15 мин
Средний
FunCTolkСравнениеSmart Contracts

Сравнение FunC и Tolk

Выбор между FunC и Tolk — это стратегическое решение, влияющее на скорость разработки, поддержку кода и привлечение новых разработчиков в проект. Понимание конкретных отличий (а не просто «Tolk новее») позволяет сделать осознанный выбор для каждого конкретного проекта. Для одних задач FunC остаётся лучшим выбором (совместимость с существующим кодом), для других Tolk предпочтительнее (новые проекты с командой).

В этом уроке мы сведём все знания о FunC и Tolk в единую картину: side-by-side сравнение синтаксиса, один и тот же контракт на обоих языках, и рекомендации по выбору.


Таблица сравнения синтаксиса

ЭлементFunCTolk
Объявление функцииint add(int a, int b)fun add(a: int, b: int): int
Неизменяемая переменнаяint x = 42;val x = 42;
Изменяемая переменнаяint x = 0; x = 1;var x = 0; x = 1;
Get-методint counter() method_idget fun counter(): int
Побочные эффектыТребует impureПо умолчанию
Чтение из Slicecs~load_uint(32)cs.loadUint(32)
Создание Cellbegin_cell()...end_cell()beginCell()...endCell()
Парсинг Cellcell.begin_parse()cell.beginParse()
Stdlib#include "stdlib.fc";Автоматический
Комментарии;; однострочный// однострочный
Точка входаrecv_internal(...)onInternalMessage(...)
Исключениеthrow(code)throw code;
Проверка условияthrow_unless(code, cond)assert(cond, code);
Inlineinline спецификатор@inline аннотация

Один контракт — два языка

Counter на FunC

#include "stdlib.fc";

;; Storage: counter (uint32)

(int) load_counter() inline {
  slice ds = get_data().begin_parse();
  return ds~load_uint(32);
}

() save_counter(int value) impure inline {
  set_data(begin_cell().store_uint(value, 32).end_cell());
}

() recv_internal(int my_balance, int msg_value, cell in_msg_full, slice in_msg_body) impure {
  if (in_msg_body.slice_empty?()) {
    return ();
  }

  int op = in_msg_body~load_uint(32);
  int query_id = in_msg_body~load_uint(64);

  if (op == 1) {  ;; increment
    int counter = load_counter();
    save_counter(counter + 1);
    return ();
  }

  if (op == 2) {  ;; decrement
    int counter = load_counter();
    throw_unless(400, counter > 0);
    save_counter(counter - 1);
    return ();
  }

  if (op == 3) {  ;; set
    int new_value = in_msg_body~load_uint(32);
    save_counter(new_value);
    return ();
  }

  throw(0xffff);
}

int counter() method_id {
  return load_counter();
}

Counter на Tolk

// Storage: counter (uint32)

fun loadCounter(): int {
    return getContractData().beginParse().loadUint(32);
}

fun saveCounter(value: int) {
    setContractData(beginCell().storeUint(value, 32).endCell());
}

fun onInternalMessage(myBalance: int, msgValue: int, msgFull: cell, msgBody: slice) {
    if (msgBody.isEndOfSlice()) {
        return;
    }

    val op = msgBody.loadUint(32);
    val queryId = msgBody.loadUint(64);

    if (op == 1) {  // increment
        val counter = loadCounter();
        saveCounter(counter + 1);
        return;
    }

    if (op == 2) {  // decrement
        val counter = loadCounter();
        assert(counter > 0, 400);
        saveCounter(counter - 1);
        return;
    }

    if (op == 3) {  // set
        val newValue = msgBody.loadUint(32);
        saveCounter(newValue);
        return;
    }

    throw 0xffff;
}

get fun counter(): int {
    return loadCounter();
}
NOTE

Оба контракта компилируются в идентичный TVM байт-код. Разница — только в синтаксисе и удобстве разработки.


Когда читать FunC

FunC остаётся важным языком для чтения, даже если вы не пишете на нём:

  • Аудит существующих контрактов — большинство production-контрактов на TON написаны на FunC
  • Системные контракты TON — Wallet V4, Elector, Config, Minter написаны на FunC
  • Исследования безопасности — отчёты аудиторов часто ссылаются на FunC код
  • Legacy-код — существующие проекты, ещё не мигрировавшие на Tolk
  • Документация TON — многие примеры в документации до сих пор на FunC

Когда писать Tolk

Tolk — рекомендуемый выбор для нового кода:

  • Все новые контракты — Tolk предлагает лучший DX без потери производительности
  • Обучение — более понятный синтаксис снижает порог входа
  • Прототипирование — быстрее писать и отлаживать
  • Браузерная разработка@ton/tolk-js позволяет компилировать в браузере
  • Миграция с FunC — компилятор поддерживает автоматическую конвертацию

Инструмент миграции

Компилятор Tolk может автоматически конвертировать FunC в Tolk:

# Конвертация одного файла
tolk --convert-from-func counter.fc > counter.tolk

Автоматическая конвертация выполняет:

ШагFunCTolk
Функцииint f(int x)fun f(x: int): int
Переменныеint x = 0;var x = 0;
Тильда-вызовыcs~load_uint(32)cs.loadUint(32)
Спецификаторыimpure, method_idУдалены / get fun
Комментарии;;//
Stdlib#include "stdlib.fc"Удалено (автоматический)

Ограничения автоконвертации:

  • Asm-вставки требуют ручной проверки
  • Нестандартные макросы не конвертируются
  • Сложные тензорные возвращаемые типы могут потребовать доработки
Проверка знанийKnowledge check
A team has a production FunC contract on mainnet and is starting a new feature. Should they migrate the existing contract to Tolk or keep it in FunC? What factors should guide this decision?
ОтветAnswer
The new feature should be written in Tolk for better developer experience with identical TVM bytecode output. The existing production contract should remain in FunC unless a major rewrite is planned -- migration introduces risk of subtle behavioral changes, and the team still needs FunC reading skills for auditing the deployed contract. The automatic converter handles simple cases, but asm-insertions and complex return types require manual review.

Переход экосистемы

Экосистема TON активно переходит на Tolk:

ПериодСтатус
2018-2024FunC — единственный язык для TVM
Июль 2025Tolk 1.0 (июль 2025) — теперь рекомендованный язык для новых контрактов; 30–50% gas savings vs FunC; фичи: nullable types, generics, smart casts, enums, unions, methods on types
2025+Tolk — default для новых контрактов; FunC остаётся для чтения legacy и аудита

Частые ошибки

  1. Выбирают язык по «новизне» а не по требованиям проекта: если проект интегрируется с существующими FunC-контрактами, FunC может быть практичнее.
  2. Смешивают FunC и Tolk в одном проекте без чёткой границы, что усложняет сборку и создаёт путаницу при аудите.
  3. Опираются на устаревшее восприятие зрелости экосистемы: Tolk 1.0 (июль 2025) — теперь рекомендованный язык для новых контрактов с 30–50% gas savings vs FunC; FunC остаётся для чтения legacy и аудита.
  4. Забывают, что оба языка компилируются в один и тот же TVM-байткод, и производительность контрактов не зависит от выбора языка.

TIP

Если начинаете новый проект — пишите на Tolk. Изучайте FunC для чтения аудитов и работы с существующими контрактами.


Итоги модуля M04

В этом модуле мы изучили:

  1. Основы FunC — типы данных, функции, точки входа контракта
  2. Чтение FunC — идиомы, op-коды, словари, разбор Wallet V4
  3. Обзор Tolk — философия, улучшения над FunC, компилятор
  4. Синтаксис Tolk — функции, типы, Cell-операции, полный контракт
  5. Оптимизация газа — упаковка, compute, storage, сообщения
  6. FunC vs Tolk — side-by-side сравнение, рекомендации

Теперь вы можете:

  • Читать существующие FunC контракты для аудита
  • Писать новые контракты на Tolk
  • Оптимизировать газ для production-контрактов
  • Понимать, когда использовать какой язык

В лабораторной работе Blueprint Docker Lab вы сможете скомпилировать и протестировать контракты локально.

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 6