Philosophy — цели, парадигма, AI-first
Решения этой группы задают рамку всех остальных: зачем нужна Nova, на
какой комбинации идей она строится, чем оптимизируется. Конкретные
правила синтаксиса и семантики — в других файлах spec/decisions/.
| # | Решение |
|---|---|
| D1 | Парадигма: protocols + data, без классов |
| D9 | Честная оценка новизны |
| D10 | Революционная ставка: «всё — эффект» + AI-first |
D1. Парадигма: protocols + data, без классов
Что
Nova — язык без классов и наследования. Данные и поведение разделены:
record-типы хранят данные, методы привязаны к типу через @-синтаксис,
структурные protocol-контракты задают «роли», use-делегация
заменяет наследование.
Правило
Четыре строительных блока, и только они:
// 1) Данные — record, sum-type, alias
type Account {
readonly owner str
balance money
}
// 2) Static-функции и конструкторы
fn Account.new(owner str) -> Account =>
Account { owner, balance: money.zero }
// 3) Методы инстанса через @
fn Account @balance() => @balance
fn Account mut @deposit(amount money) {
@balance += amount
}
// 4) Структурный контракт через protocol
type Hashable protocol {
hash() -> u64
eq(other Self) -> bool
}
Замена наследования — use name Type внутри type (alias
обязателен, D39):
type AuditedAccount {
use account Account // delegation, не наследование
audit_log []AuditEntry
}
Компилятор генерирует прокси-методы; AuditedAccount не подтип
Account. Подробно — 02-types.md → D39.
Почему
- Наследование — известный антипаттерн. Fragile base class, diamond problem, божественные классы. Go доказал, что без классов можно жить; Rust — что без GC и наследования можно писать сложные системы; OCaml — что sum-types убивают половину паттернов GoF.
- Структурно, а не номинально. Любой тип со совпадающими методами
автоматически удовлетворяет
protocol-контракту. Никакихimpl Trait for Type-блоков (как в Rust). - Локальность чтения. Метод привязан к типу через
fn Type @method, виден рядом с типом, не размазан поimpl-блокам.
Что отвергнуто
- Классы и наследование. Антипаттерн, см. выше.
trait+impl Trait for Type(Rust-стиль). Заменено на структурныйprotocol(D9, D42) — безimpl-блоков.mut selfкак параметр. Заменено наfn Type mut @method()— модификатор перед@. См. 03-syntax.md → D35.
Связь
- 02-types.md → D9,
D42 —
protocolкак механизм контрактов. - 02-types.md → D39 —
useдля delegation. - 03-syntax.md → D35 — методы через
@. - 01-philosophy.md → D10 — обоснование выбора в рамках общей AI-first ставки.
Эволюция
В ранних черновиках использовались Rust-style trait /
impl Trait for Type. Отказались в пользу структурного protocol
(D42) — без явного impl-блока, по совпадению
методов. Старая модель (trait/impl) ещё описана в paradigm.md,
файл помечен устаревшим до полной переписи. См.
history/evolution.md.
D9. Честная оценка новизны
Что
Nova не изобретает ни одной фичи в одиночку — каждая идея уже где-то есть. Заявка на новизну — сочетание идей в одном прикладном языке. Это слабая заявка, которую нужно держать честно перед глазами, чтобы дизайн не превращался в «всего понемногу».
Откуда взяты идеи
| Идея | Источник |
|---|---|
| Effect system | Koka, Effekt, Eff |
| Регионы памяти | Zig, Odin, Cyclone |
protocol + sum-types | Swift, Rust, OCaml |
| Структурная типизация | Go, TypeScript |
| Три режима компиляции | Julia |
| Embed-delegation | Go |
Мономорфизация + dyn | Rust |
| Fiber runtime | Go, OCaml 5, Erlang |
Контракты (requires/ensures) | Eiffel, Spec#, Dafny |
Почему «языки-комбинаторы» проваливаются
Scala, D, Nim, Crystal — все технически сильные, ни один не доминирует. Языки выигрывают не фичами, а экосистемой + killer use-case:
- Go — серверы (Google + Docker/Kubernetes).
- Rust — системное (Mozilla + Linux kernel).
- Python — ML (NumPy / PyTorch).
- TypeScript — фронт (Microsoft + VS Code).
У гипотетической Nova ни одного из этих рычагов нет.
Две вещи, которые могли бы быть реально новыми
Если выбирать одно предложение на вопрос «зачем переходить с того, что есть» — это:
1. Effect system в прикладном языке с понятными ошибками.
Koka/Effekt/Eff — академические, на них никто не пишет в продакшне.
Нет ни одного прикладного языка, где effects заменили
async/throws/unsafe одновременно и были бы понятны программисту
с Java-фоном за день. Решающая инженерная задача — сообщения
компилятора про эффекты. В Koka они академически точны и
человечески непонятны. Никто пока эту задачу не решил.
2. Три режима компиляции (AOT/JIT/интерпретатор) в строго
типизированном языке без жертв. Julia умеет JIT+AOT, но типизация
слабая. C# умеет AOT+JIT, но REPL ограниченный. Go умеет AOT, REPL
нет. TypeScript = только интерпретация. Nova могла бы быть первым
строго типизированным языком, где nova run script.nv работает как
Python, а nova build даёт бинарь как Go — без переписывания.
Что не является заявкой
protocols + data, регионы памяти, structured concurrency,
sum-types — это повторение лучших практик. Нужно, чтобы язык
вообще был хорошим, но не отличает Nova от Rust/Swift/Kotlin.
Заявлять «у нас sum-types» в 2026 — как заявлять «у нас замыкания»
в 2010. Базовый санитар.
Главный вывод для дизайна
Если очередная идея не усиливает одну из двух уникальных заявок выше, а просто «делает язык хорошим» — её добавлять можно, но не надо выдавать за отличие. И до написания компилятора нужно ответить письменно: «зачем мне переходить с X на Nova одним предложением». Большинство языков-неудачников начали с компилятора, а не с этого вопроса.
Связь
- 01-philosophy.md → D10 — D9 ставит вопрос, D10 даёт ответ через ставку «всё эффект + AI-first».
- 04-effects.md — реализация effect system.
- 08-runtime.md → D7 — три режима компиляции.
D10. Революционная ставка: «всё — эффект» + AI-first
Что
Nova переходит от «хорошего языка с набором фич» к языку с одной центральной абстракцией и одним killer use-case. Центральная абстракция — алгебраические эффекты. Killer use-case — AI-first язык, оптимизированный под пару «LLM пишет, человек ревьюит».
Центральная абстракция: всё — эффект
Не просто Fail/Io. Любое взаимодействие с внешним миром —
эффект: аллокация в region (Alloc[R]), время (Time),
случайность (Random), сеть (Net), БД (Db), файлы (Fs),
лог (Log), и пользовательские эффекты, которые программист
объявляет сам через effect keyword
(D61). Эффекты алгебраичны (Koka/Effekt-style):
у каждого есть handler — функция, перехватывающая эффект и
решающая, что с ним делать.
(Suspension и параллелизм — runtime-инфраструктура, не эффекты;
см. D62, D14,
D50. Изменяемое состояние — через mut
поля и параметры, не эффект Mut.)
Из этой одной идеи следует всё:
- Тестирование без моков = подмена handler’а.
- Транзакции = handler эффекта
Db. - Undo/redo = handler специализированного state-эффекта
(
Counter,History— каждый со своим именем; genericMutудалён в D62). - Детерминированный запуск = handler
Time+Randomс фиксированными значениями. - Трассировка = handler-обёртка над любым эффектом.
- Capability security = разрешённые handler’ы в скоупе.
Подробно — 04-effects.md.
Killer use-case: AI-first язык
LLM пишет 50–80% кода в 2026+. Все существующие языки спроектированы до этой эпохи, под человека. Nova явно оптимизирует под пару «LLM пишет, человек ревьюит»:
- Локальность контекста — функция понятна без 10 файлов вокруг (нет неявных импортов, нет DI через рефлексию, нет хуков-невидимок).
- Сигнатура = полное описание поведения — типы + эффекты + pre/postconditions, читая сигнатуру знаешь всё.
- Ошибки компилятора как обучающий сигнал — формат, по которому LLM фиксит код за одну итерацию, без человека-посредника.
- Стабильность синтаксиса — никаких революций каждые 2 года, LLM учится на старых данных.
- Проверяемость по фрагменту — типечекинг одной функции без всего проекта.
- Эффекты делают код безопасным для AI-генерации — невозможно «случайно» сходить в сеть/БД, это видно в сигнатуре.
Почему это связано в одно
Эффекты дают LLM то, чего у него нет ни в одном языке: полную видимость побочных действий по сигнатуре. Когда LLM пишет функцию, у него нет способа узнать, ходит ли вызываемый код в сеть. В Nova это в типе. Это превращает «вероятностный код от LLM» в «верифицируемый код от LLM» — и это уникальная заявка, та самая, на которую указывает D9.
Что выкидывается из прежнего дизайна
- «Хороший язык в духе Swift/Kotlin» как цель — заменено на конкретную ставку.
- «Всего понемногу» (Go + Rust + OCaml + Julia) — теперь Nova следует из одной идеи, а не комбинирует пять.
- Effects как «ещё одна фича рядом с traits» — теперь это центр.
Что остаётся
protocols+data(D1) — следствие «всё эффект»: метод протокола может иметь эффект.- Managed memory (05-memory.md → D6) — программист
пишет без префиксов памяти. Real-time зоны через эффект
Realtime(тело оборачивается в region автоматически). - Три режима компиляции (08-runtime.md → D7) — handler’ы перехватываются и в JIT, и в AOT, и в интерпретаторе одинаково.
- Структурная типизация — без изменений (D9 / D42).
Что добавляется
- Handler-блоки — синтаксис подмены эффектов
(
with Effect = handler { ... }). - Capability-режим — функция декларирует, какие эффекты разрешены
в её скоупе (
forbid Net, Fs { body }). - Контракты —
requires/ensures/invariantкак часть сигнатуры (09-tooling.md → D24). - Детерминированный режим тестирования — встроенный handler-стек, фиксирующий время/случайность/IO.
Цена и риски
- Effect system сложнее в реализации. Алгебраические эффекты с handler’ами — нетривиальный compilation target. Koka и Effekt академические, не показывают production-grade перформанс.
- AI-first как позиционирование требует, чтобы Nova стабильно выдавала качественный LLM-код уже в v0.1. Это означает упор на стабильность синтаксиса и качество ошибок с самого начала.
- Узкая ставка — если AI-first не «выстрелит», Nova остаётся ещё одним «языком-комбинатором» (см. D9).
Связь
- 01-philosophy.md → D1 — парадигма как следствие.
- 04-effects.md — реализация центральной абстракции.
- 09-tooling.md → D24 — контракты как AI-инструмент.
- 05-memory.md → D6, 06-concurrency.md → D14, 08-runtime.md → D7 — что остаётся как фундамент.
Эволюция
D10 пересматривает раннюю позицию «хороший язык в духе Swift/Kotlin». Подробно — history/evolution.md.