Язык Goose обещает обогнать C++ и Rust: без кучи и сборщика мусора
Goose, язык программирования, который на странице проекта назван безопасным по памяти системным языком без аллокатора кучи, сборщика мусора и аннотаций времён жизни. Синтаксис знаком программистам на C и Rust, но кучи нет вообще: каждое динамическое значение лежит прямо в стеке данных, которым управляет компилятор. Рост структуры сдвигает указатель, а память освобождается при выходе из области видимости. Безопасность обеспечивают правила типов и времён жизни, которые компилятор выводит сам.
Главное заявление: в собственных тестах репозитория по шестнадцати бенчмаркам Goose работает в 3,3 раза быстрее идиоматичного C++, в 1,16 раза быстрее вручную оптимизированного C++ и в 1,12 раза быстрее лучшего безопасного Rust. При этом памяти он тратит в 1,9, 1,3 и 1,2 раза меньше соответственно. Выигрыш авторы страницы связывают с раскладкой данных и моделью памяти.
Как это устроено. Память, это несколько стеков данных, которые компилятор назначает статически. Освобождение структуры на миллион элементов, одна операция записи, как бы глубоко она ни была вложена. В стеке допускается не более одного изменяемого по размеру значения, и оно всегда на вершине, поэтому рост ничего не перемещает и не проверяет ёмкость; это, по заявлению страницы, доказывается на этапе компиляции. Ссылка на элемент растущего массива остаётся действительной, пока жив сам массив: там, где в C++ нужен reserve, а в безопасном Rust в соответствующих бенчмарках используются индексы u32, в Goose хранятся типизированные ссылки.
Вложенные данные лежат подряд. Строка, массив строк, запись с полями переменного размера и массив таких записей, каждое это один непрерывный блок без указателей. Пример со страницы: заказ с именем клиента и списком позиций занимает в Goose 29 байт и ни одного выделения памяти; в C++ с std::string и std::vector это 160 байт и одно выделение, в Rust с String и Vec, 153 байта и четыре выделения. Цена такого подхода: массив элементов переменного размера последовательный, его можно перебирать, но нельзя индексировать (если только не вести второй массив ссылок).
Другие особенности из описания. Перечисления (ADT) в переменном режиме занимают ровно столько, сколько нужно конкретному варианту; на единственном бенчмарке, где это проверяется, выигрыш против enum в Rust, 4 раза по памяти и 2 раза по скорости. Относительные ссылки хранят проверяемую связь как смещение в 1, 2 или 4 байта, а обычная ссылка T&, машинный адрес в восемь байт. Бинарное дерево поиска из таких ссылок имеет 12-байтные узлы. Раз структуры не зависят от положения в памяти, данные сами являются форматом файла: сохранение, запись, загрузка, чтение плюс проверка; from_bytes проверяет разметку, теги, длины и ссылки, так что повреждённый или враждебный файл даёт false, а не «дикую» ссылку.
Возврат ошибок через несколько вызовов выполняется командой return err from load, статически проверяемо, без раскрутки стека и без типа Result. Потоки ничего не разделяют: рабочий поток компилируется как отдельная программа со своей памятью, плоские значения передаются через типизированные очереди копированием, поэтому гонок данных, блокировок, атомарных операций и порядков памяти в языке нет. Обобщённые функции и функции высшего порядка не добавляют накладных расходов. Goose компилируется в один файл на C, напрямую вызывает C через extern fn, а встроенный бэкенд TinyCC компилирует и запускает программу в процессе без отдельной сборки. На странице есть руководство, справочник, спецификация, пакеты, бенчмарки и тридцать один готовый пример.
Ключевые факты
- Goose, системный язык с безопасной работой с памятью, но без кучи, сборщика мусора, подсчёта ссылок и аннотаций времён жизни: динамические значения лежат в стеках данных, которыми управляет компилятор.
- По шестнадцати бенчмаркам самого репозитория Goose быстрее идиоматичного C++ в 3,3 раза, оптимизированного вручную C++ в 1,16 раза и лучшего безопасного Rust в 1,12 раза, с расходом памяти меньше в 1,9, 1,3 и 1,2 раза.
- Вложенные данные хранятся непрерывно и без указателей: пример заказа занимает 29 байт и 0 выделений против 160 байт в C++ и 153 байт с четырьмя выделениями в Rust.
- Гонок данных, блокировок и атомарных операций в языке нет: каждый рабочий поток, отдельная программа со своей памятью.
- Компилятор выдаёт один файл на C, умеет вызывать C напрямую и содержит встроенный TinyCC для запуска без отдельной сборки; цена модели, массивы элементов переменного размера нельзя индексировать.
Почему это важно
Goose предлагает необычный компромисс: безопасность памяти без сборщика мусора и без сложных правил заимствования, как в Rust. Вместо кучи, стеки данных с выделением и освобождением сдвигом указателя. Если заявленные цифры подтвердятся, язык показывает, что за счёт раскладки данных можно выиграть и в скорости, и в памяти у C++ и безопасного Rust. Пока это утверждение самой страницы проекта.
Кому это важно
Разработчикам системного ПО, которых интересуют альтернативы C++ и Rust, авторам языков и компиляторов, а также тем, кто занимается производительностью и раскладкой данных в памяти (например, хранением данных подряд и форматами файлов без сериализации).
Как это применить
На странице проекта есть руководство, справочник, спецификация, пакеты, стандартная библиотека и тридцать один пример полных программ. Компилятор выдаёт один файл на C, а встроенный бэкенд TinyCC позволяет запускать программу в процессе без шага сборки, так что попробовать язык можно на примерах. Сведений о версии, лицензии и готовности к промышленному использованию в разобранном фрагменте нет.
Можно ли доверять
Все цифры о превосходстве над C++ и Rust взяты из бенчмарков самого репозитория, а ссылка на результаты ведёт на отдельную страницу. В разобранном фрагменте не описаны методика, железо, компиляторы и флаги, не приведены результаты по отдельным бенчмаркам, а о независимой проверке или воспроизведении ничего не сказано. Ускорение в 3,3 раза по шестнадцати бенчмаркам относится к идиоматичному C++, а против оптимизированного вручную C++ и лучшего безопасного Rust преимущество скромнее, 1,16 и 1,12 раза. Автор, организация и дата проекта в тексте не названы.
Риски и подводные камни
Сам проект называет цену модели: массив элементов переменного размера последовательный, его можно перебирать, но нельзя индексировать без второго массива ссылок. В переменном режиме перечислений значение не меняет вариант. Выигрыш в 4 раза по памяти и 2 раза по скорости против enum из Rust получен на единственном бенчмарке, где это проверяется. Фрагмент текста обрывается на примере возврата ошибок, поэтому остальные разделы здесь не учтены.
«Безопасный по памяти системный язык без аллокатора кучи, сборщика мусора и аннотаций времён жизни.»
— страница проекта Goose