Сравнение FunC и Tolk
Выбор между FunC и Tolk — это стратегическое решение, влияющее на скорость разработки, поддержку кода и привлечение новых разработчиков в проект. Понимание конкретных отличий (а не просто «Tolk новее») позволяет сделать осознанный выбор для каждого конкретного проекта. Для одних задач FunC остаётся лучшим выбором (совместимость с существующим кодом), для других Tolk предпочтительнее (новые проекты с командой).
В этом уроке мы сведём все знания о FunC и Tolk в единую картину: side-by-side сравнение синтаксиса, один и тот же контракт на обоих языках, и рекомендации по выбору.
Таблица сравнения синтаксиса
| Элемент | FunC | Tolk |
|---|---|---|
| Объявление функции | 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_id | get fun counter(): int |
| Побочные эффекты | Требует impure | По умолчанию |
| Чтение из Slice | cs~load_uint(32) | cs.loadUint(32) |
| Создание Cell | begin_cell()...end_cell() | beginCell()...endCell() |
| Парсинг Cell | cell.begin_parse() | cell.beginParse() |
| Stdlib | #include "stdlib.fc"; | Автоматический |
| Комментарии | ;; однострочный | // однострочный |
| Точка входа | recv_internal(...) | onInternalMessage(...) |
| Исключение | throw(code) | throw code; |
| Проверка условия | throw_unless(code, cond) | assert(cond, code); |
| Inline | inline спецификатор | @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();
}
Оба контракта компилируются в идентичный 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
Автоматическая конвертация выполняет:
| Шаг | FunC | Tolk |
|---|---|---|
| Функции | 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-вставки требуют ручной проверки
- Нестандартные макросы не конвертируются
- Сложные тензорные возвращаемые типы могут потребовать доработки
Проверка знаний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?
Переход экосистемы
Экосистема TON активно переходит на Tolk:
| Период | Статус |
|---|---|
| 2018-2024 | FunC — единственный язык для TVM |
| Июль 2025 | Tolk 1.0 — официальный релиз |
| 2025+ | Tolk — рекомендуемый язык для нового кода |
| Будущее | FunC остаётся для чтения legacy, Tolk — для разработки |
Частые ошибки
- Выбирают язык по «новизне» а не по требованиям проекта: если проект интегрируется с существующими FunC-контрактами, FunC может быть практичнее.
- Смешивают FunC и Tolk в одном проекте без чёткой границы, что усложняет сборку и создаёт путаницу при аудите.
- Не учитывают зрелость экосистемы: для FunC больше примеров, аудитов и инструментов; для Tolk — лучше документация и DX.
- Забывают, что оба языка компилируются в один и тот же TVM-байткод, и производительность контрактов не зависит от выбора языка.
Если начинаете новый проект — пишите на Tolk. Изучайте FunC для чтения аудитов и работы с существующими контрактами.
Итоги модуля M04
В этом модуле мы изучили:
- Основы FunC — типы данных, функции, точки входа контракта
- Чтение FunC — идиомы, op-коды, словари, разбор Wallet V4
- Обзор Tolk — философия, улучшения над FunC, компилятор
- Синтаксис Tolk — функции, типы, Cell-операции, полный контракт
- Оптимизация газа — упаковка, compute, storage, сообщения
- FunC vs Tolk — side-by-side сравнение, рекомендации
Теперь вы можете:
- Читать существующие FunC контракты для аудита
- Писать новые контракты на Tolk
- Оптимизировать газ для production-контрактов
- Понимать, когда использовать какой язык
В лабораторной работе Blueprint Docker Lab вы сможете скомпилировать и протестировать контракты локально.
Check Your Understanding
Finished the lesson?
Mark it as complete to track your progress
Войдите чтобы оценить урок