Goose - экспериментальный язык программирования и компилятор, который спроектировал Wouter van Oortmerssen. Этот же человек начал в 2010 году разработку языка Lobster и связан с библиотекой сериализации FlatBuffers, опубликованной Google в 2014-м.
Шум вокруг проекта объясняется происхождением кода: реализацию компилятора, бенчмарки, примеры и документацию почти полностью создала ИИ-модель Claude (в разборе на Habr она названа Claude Fable). В репозитории сказано прямо: проект произведен почти целиком с помощью AI, от человека остался дизайн языка. Формулировка «ИИ написал язык» неточная. Язык придумал человек, а код по этому замыслу сгенерировала модель.
Техническое ядро - управление памятью на аренах и bump-аллокаторах. Компилятор заранее вычисляет число data stacks, а данные освобождаются целыми областями видимости: без сборщика мусора и без аннотаций времени жизни. Обещание сильное, поэтому сразу оговорка: Goose не замена C++ или Rust. Это нишевый инструмент, и цену за его модель памяти платят ограничениями языка.
Честный тон задает сам автор: заявленные цифры производительности он сопровождает оговорками о шуме измерений, ограничениях методики и проигрышах в части задач. Держать эти оговорки в голове придется всю статью.
Что такое Goose и почему вокруг него столько шума
Goose интересен двумя вещами одновременно. Первая - модель памяти, которая обещает безопасность и скорость без сборщика мусора и без lifetime-аннотаций. Вторая - процесс создания: почти весь код написан ИИ по человеческому проекту языка.
Кто такой Wouter van Oortmerssen и при чем тут Lobster и FlatBuffers
Lobster - собственный язык автора, его разработка началась в 2010 году. FlatBuffers - библиотека сериализации, которую Google опубликовал в 2014-м; она строится вокруг доступа к данным без лишнего копирования и распаковки. Оба проекта говорят об одном: перед нами не случайный энтузиаст, а человек с опытом проектирования языков и работы с производительной обработкой данных.
Для оценки Goose это важно, но не отменяет главного: проект молодой и экспериментальный. Опыт автора не заменяет зрелости экосистемы, библиотек и независимых замеров.
Что именно сделал ИИ, а что человек
Разделение простое. Человек отвечает за дизайн: какие конструкции есть в языке, как устроена память, какие ограничения допустимы. Claude отвечает за реализацию: код компилятора, набор бенчмарков, примеры и документацию. Обычно модель дописывает функции внутри готового проекта, здесь она собрала проект вокруг человеческого замысла языка.
Такая постановка интересна сама по себе, но требует критического чтения. Бенчмарки и документацию писал тот же инструмент, что и компилятор. Значит, возможны систематические смещения: тесты меряют то, что компилятор уже умеет, а описание повторяет замысел автора без проверки на чужих сценариях. Цифры и формулировки из репозитория стоит воспринимать как заявку, а не как независимое измерение.
Модель памяти Goose: арены, bump-аллокаторы и области видимости
К управлению памятью автор предъявляет три нефункциональных требования, в источнике они сформулированы «на букву Б»: Безопасно; Без затей, то есть без сложных действий вроде явных аннотаций времени жизни; Быстро, то есть выделение и освобождение требуют минимальной и предсказуемой работы во время выполнения. Четвертое требование - «Бережно»: минимум памяти на служебные данные.
Обычно язык закрывает два пункта из трех и платит третьим. Goose заявляет все четыре сразу.
Почему это называют «безопасностью без GC и без lifetime-аннотаций»
Safe Rust дает безопасность памяти и исключает гонки данных, работает без сборщика мусора. Плата - «магические руны» в сигнатурах функций:
fn longest<'a>(a: &'a str, b: &'a str) -> &'a str {
if a.len() >= b.len() { a } else { b }
}
Go и JavaScript проще, зато допускают гонки данных: в Go между goroutines, работающими с общей памятью, в JavaScript между agents (например, Web Workers), обращающимися к одному SharedArrayBuffer. Dart исключает гонки над управляемой памятью в чистом коде благодаря модели isolates, но эта гарантия не распространяется на FFI и JavaScript-интероп.
Goose пробует другой обмен: ограничения языка вместо аннотаций в коде. Что именно придется отдать взамен, разбираем ниже.
Как компилятор считает data stacks и освобождает области видимости
Механика опирается на две вещи: арены, то есть области памяти, из которых выделяются объекты, и bump-аллокатор внутри каждой арены. Bump-аллокатор работает как сдвиг указателя: новый объект получает следующий кусок памяти, отдельного освобождения нет. Когда область видимости заканчивается, вся арена сбрасывается целиком.
Компилятор статически вычисляет число data stacks, то есть заранее знает, сколько таких областей понадобится программе. Отсюда свойства: нет пауз сборщика мусора, нет счетчиков ссылок, нет заголовков служебных данных у каждого объекта. Выделение сводится к прибавлению к указателю, освобождение к его сбросу назад. Именно на этом «Бережно» и держится: служебные расходы памяти близки к нулю, потому что учитывать отдельные объекты не нужно.
Для программиста меняется единица мышления. Думать нужно не об отдельных объектах, а о группах данных и о моменте, когда группа умирает. Если этот момент совпадает с выходом из области видимости, модель работает идеально. Если нет, начинаются обходные пути.
Детали реализации в доступном описании не раскрыты: фрагмент, где автор начинает объяснять устройство data stacks, обрывается. Уверенно утверждать можно одно - освобождение привязано к областям видимости, а не к отдельным значениям.
Бенчмарки: где Goose быстрее C++ и Rust, а где нет
По описанию проекта автор приводит замеры, где Goose под Clang обгоняет оптимизированный C++ и safe Rust более чем на 10% и заметно экономит память. Это цифры из одной публикации, а не результат независимой проверки.
Оговорки делает сам автор: шум измерений, ограничения методики, проигрыши в ряде задач. Читать заявления стоит вместе с ними, иначе получается реклама.
Почему преимущество «более 10%» не приговор для C++ и Rust
Разница зависит от трех вещей: задачи, компилятора и характера нагрузки. В источнике указан Clang, но конкретные флаги, версии, наборы тестов и конфигурация железа в доступном фрагменте не раскрыты. Формулировка «оптимизированный C++» требует расшифровки: что именно оптимизировали, какими аллокаторами пользовались, включали ли межпроцедурную оптимизацию и профилирование.
Отдельный риск - происхождение тестов. Бенчмарки писал тот же ИИ-инструмент, что и компилятор. Возможны сценарии, где замер случайно удобен для Goose: например, нагрузка целиком укладывается в модель арен и не требует долгоживущих объектов. Проигрыши в части задач автор упоминает, но их состав в доступном тексте не приведен.
Практический вывод: цифры полезны как сигнал, что модель памяти как минимум не медленнее традиционных подходов. Решение о языке строят на своем замере. Взять типичную для проекта нагрузку, собрать оба варианта и сравнить не только время работы, но и пиковое потребление памяти.
Цена модели памяти: ограничения, которые придется принять
Ограничения Goose вытекают из модели памяти. Если память освобождается областями, свободно таскать ссылки на данные через замыкания и общую память нельзя: тогда непонятно, когда область можно сбросить. Ниже четыре ограничения из источника и то, что каждое означает для кода.
Замыкания и function values: что именно нельзя
В Goose есть ограничения на замыкания и function values. На практике это касается привычных паттернов: колбэки, передача функции как значения, захват окружения, фабрики функций. Такие конструкции предполагают, что функция живет дольше данных, которые она захватила, а модель арен такому сценарию сопротивляется.
Насколько ограничение жесткое, из доступного описания не видно: в источнике тема только заявлена в оглавлении, содержание раздела не раскрыто. Планировать архитектуру на догадках не стоит, лучше свериться с примерами в репозитории.
Многопоточность без общей изменяемой памяти
Общей изменяемой памяти между потоками в Goose нет. Данные передаются только через типизированные очереди. Это убирает целый класс ошибок: гонки данных, которые в Go возникают между goroutines с общей памятью, а в JavaScript между agents через SharedArrayBuffer, здесь просто не выразить.
Взамен программист строит обмен сообщениями. Модель ближе к акторам и каналам, чем к потокам с мьютексами: состояние принадлежит одному потоку, остальные получают сообщения. Для конвейеров обработки это удобно. Для сценариев, где несколько потоков правят одну большую структуру, неудобно настолько, что проще взять другой язык.
Массивы элементов разного размера и другие структурные запреты
Индексировать массивы элементов разного размера нельзя. Связь с аренами прямая: однородные элементы фиксированного размера укладываются в bump-аллокатор предсказуемо, а разнородные ломают картину и требуют того самого точечного управления памятью, от которого Goose уходит.
Следствие для дизайна: структуры данных проектируются под однородность. Вместо массива указателей на разнотипные узлы появляется несколько однородных массивов или тегированная раскладка, где все элементы одного размера. Прием классический для парсеров и компиляторов, и он же объясняет, почему Goose тянет именно к таким задачам.
Все четыре ограничения - не баги и не недоделки. Это плата за безопасность без сборщика мусора и без аннотаций времени жизни, и плата вполне конкретная: часть привычных архитектур в языке не выражается.
Для каких задач Goose реально подходит
Ниша проекта задана его моделью памяти: парсеры, компиляторы, пакетная обработка. Общее свойство этих задач: данные живут группами и освобождаются целиком.
Парсеры, компиляторы и пакетная обработка: почему именно они
Разбор текста строит дерево. Узлы AST создаются на время прохода и умирают вместе с ним, отдельный узел почти никогда не переживает фазу. Значит, арена под проход - естественная единица освобождения. Компилятор добавляет вторую фазу, например обход типов, и каждая фаза получает свою область.
Пакетная обработка устроена похоже: данные приходят пачками, пачка обрабатывается и сбрасывается. Единица освобождения - пакет, а не запись. Ни долгоживущего состояния с точечным освобождением, ни сложных графов владения здесь не возникает, поэтому цена ограничений почти не ощущается.
Именно на таких нагрузках арены дают выигрыш: память выделяется одним сдвигом указателя, а сброс арены стоит примерно ничего. Никаких пауз на уборку мусора посреди обработки.
Где Goose проигрывает и где его лучше не использовать
Антипаттерны по пунктам:
- Долгоживущее состояние с точечным освобождением: кэши, сессии, структуры, которые живут часами и меняются по частям.
- Активная многопоточность с общей изменяемой памятью: модель Goose такое просто не выражает.
- Архитектура на замыканиях и function values: колбэки, обработчики событий, функциональные цепочки.
- Массивы разнородных элементов: коллекции, где рядом лежат объекты разного размера.
Отдельный пункт - зрелость. Проект экспериментальный, экосистемы и инструментов вокруг пока нет. Для продакшена это значит отсутствие библиотек, отладчиков с поддержкой языка, накопленных рецептов и людей, которые уже набили шишки на типовых ошибках.
Goose против C++, Rust, Go и Dart: честное сравнение
Сравнение по критериям из источника: безопасность памяти, простота, скорость, плюс бережливость по служебным расходам памяти.
| Язык | Безопасность памяти | Простота | Скорость | Примечание |
|---|---|---|---|---|
| Go | С оговорками: гонки данных между goroutines с общей памятью | Высокая | Частично | Не требует аннотаций времени жизни |
| JavaScript | С оговорками: гонки между agents через SharedArrayBuffer | Высокая | Частично | Тот же компромисс, что в Go |
| Dart | Да, в чистом коде за счет модели isolates | Высокая | Частично | Гарантия не покрывает FFI и JavaScript-интероп |
| Rust | Да, включая запрет гонок данных | Низкая: аннотации времени жизни | Да | Статические гарантии оплачены текстом программы |
| Goose | Заявлена | Заявлена | Заявлена, замеры под Clang | Четвертое требование - бережливость памяти; статус экспериментальный |
Таблица показывает расклад: каждый зрелый язык осознанно отдает один пункт. Goose пытается не отдавать ничего, но переносит цену в ограничения языка и в отсутствие экосистемы. Для большинства проектов выбор остается между зрелыми языками. Goose имеет смысл там, где нагрузка совпадает с его сильной стороной, а не там, где нужно переписать существующий сервис.
Что значит «язык, написанный ИИ» для доверия к проекту
Плюсы очевидны. Язык с компилятором, бенчмарками и документацией появился за сроки, немыслимые для классической разработки. Кейс показывает, где ИИ уже полезен: рядовую реализацию по четко сформулированному техническому замыслу он тянет.
Риски тоже конкретные. Бенчмарки и документацию писал тот же инструмент, что и компилятор, поэтому систематические ошибки могут быть согласованы между собой: тест меряет то, что компилятор умеет, а описание рассказывает то, что задумано. Независимой проверки в доступных материалах нет.
Совет практический: смотреть исходники и примеры, а не только описание, и проверять утверждения на своих задачах. Похожий процесс, только про синтаксис, разобран в материале о том, как автор языка Nova спорил с Claude о конструкциях языка: 11 споров с Claude о синтаксисе. Там видно, в каких местах модель защищает записанное по инерции, а где оказывается права. Для Goose рамка чтения такая же: дизайн человеческий, реализация машинная, проверка на читателе.
Итог: кому и зачем нужен Goose
Goose - эксперимент на стыке дизайна языков и AI-разработки. Ценность проекта в демонстрации модели памяти: арены и bump-аллокаторы, число data stacks, известное компилятору заранее, освобождение данных областями видимости. Это обещает безопасность и скорость без сборщика мусора и без аннотаций времени жизни.
Цена - ограничения: замыкания и function values, отсутствие общей изменяемой памяти между потоками, обмен только через типизированные очереди, запрет на индексацию массивов элементов разного размера. Каждое отсекает целый класс задач.
Кому смотреть: тем, кто проектирует парсеры, компиляторы и пакетную обработку, где данные живут группами; тем, кто изучает AI-инструменты разработки и хочет увидеть масштаб того, что модель уже способна собрать по человеческому дизайну.
Кому не смотреть: тем, кто ищет замену C++ или Rust в продакшене. Зрелости, библиотек и независимых замеров здесь пока нет.
Проверить утверждения можно по исходникам автора: разбор Goose на Habr со ссылками на репозиторий, примерами и бенчмарками. Читать стоит вместе с оговорками самого автора о шуме и методике, а лучше - вместе со своим замером на своей задаче.