Комментарии (8)
When you want to embed a type, you need its definition, but you don’t actually need the full definition. You just need the size/alignment.Aren't there ABI cases where e.g. struct foo { float X, Y; } would be passed in e.g. fp registers whereas struct { char[8]; } would not? Thi
Why is Zig so cool? 🔥 Горячее 💬 Длинная дискуссия
Zig - это не просто замена C или C++, а совершенно новый подход к программированию, который удивил автора с 45-летним опытом. Самые впечатляющие особенности языка - встроенная возможность компилировать C-код и кросс-компиляция "из коробки", что уже оказывает значительное влияние на индустрию.
Установка компилятора Zig проста и доступна для различных платформ и архитектур на официальном сайте. Автор подчеркивает, что эти функции сами по себе уникальны, но сосредоточен на том, как программировать на Zig и почему стоит выбрать его вместо других языков.
Комментарии (467)
- Статья преувеличивает инновативность Zig, не подкрепляя заявления о "революционности" реальными уникальными фичами.
- Пользователи отмечают практические преимущества: простота установки (через PyPI), кросс-компиляция, явный синтаксис и компиляция C-кода.
- Критика включает отсутствие безопасности памяти, спорные решения (политика идентификаторов, отсутствие данных в ошибках) и сравнение с Rust/Ada как более зрелых альтернатив.
- Отдельные хвалят метапрограммирование (comptime), простоту навигации по коду и удобство для низкоуровневого программирования.
- Обсуждение подчеркивает субъективность восприятия: для одних Zig "меняет подход к программированию", для других — лишь "улучшенный C" без уникального позиционирования.
Dependent types and how to get rid of them
Зависимые типы позволяют создавать более точные типы, которые могут зависеть от значений, но их обработка компиляторами различается. В отличие от обычных типов, которые полностью стираются во время компиляции, зависимые типы могут частично сохраняться в исполняемом коде. Это влияет на производительность и возможности оптимизации.
Исследования показывают, что некоторые языки с зависимыми типами, такие как Idris, сохраняют часть информации о типах во время выполнения. Это позволяет выполнять проверки типов во время выполнения, открывая новые возможности для метапрограммирования и рефлексии. Однако такая сохранение типов увеличивает размер исполняемых файлов и может снижать производительность.
Комментарии (60)
- Обсуждение показало, что зависимые типы (dependent types) — это не только академическая концепция, но и практически применимы в языках вроде Zig и TypeScript, хотя с ограничениями.
- Участники обсуждали, что в TypeScript условные типы и в Zig
comptimeдемонстрируют схожие с зависимыми типами идеи, но не покрывают полный спектр возможностей зависимых типов. - Были подняты вопросы о том, что такое "зависимые типы" и как они отличаются от обычных обобщённых типов, с упором на то, что в большинстве языков нет полной поддержки зависимых типов.
- Обсуждались примеры, где тип возвращаемого значения может зависеть от входного значения, и как это может быть реализовано в разных языках.
- Также обсуждались границы между статическим и динамическим анализом типов, и как они влияют на возможность компилятора вычислять и оптимизировать код.
State of Terminal Emulators in 2025: The Errant Champions 💬 Длинная дискуссия
В 2025 году обновился инструмент ucs-detect для проверки поддержки Unicode в эмуляторах терминалов, теперь тестирующий DEC Private Modes, sixel-графику, размер пикселей и версию ПО. Методика проверки основана на отправке видимого текста с последующими управляющими последовательностями для определения позиции курсора, с сравнением результатов со стандартом Python wcwidth. Основная проблема эмуляторов — корректное отображение широкого спектра Unicode-символов в фиксированной сетке без нарушения читаемости.
Лидером тестов стал новый эмулятор Ghostty, разработанный с нуля на языке Zig и показавший наилучшую поддержку Unicode. Почти не уступил ему Kitty, реализовавший алгоритм разбиения текста, близкий к спецификации Python wcwidth. Оба эмулятора корректно поддерживают Variation Selector 15. Среди неожиданных результатов — низкая производительность: iTerm2 и Extraterм потребляли чрезмерное количество CPU, а GNOME Terminal на базе VTE работал более 5 часов. Полные результаты доступны на сайте проекта.
Комментарии (226)
- Терминалы варьируются от полной поддержки Unicode до полного отсутствия поддержки, что делает выбор сложным, особенно для пользователей, которым важна поддержка Unicode.
- Некоторые эмуляторы, такие как Konsole, поддерживают широкий спектр Unicode, в то время как другие могут не поддерживать даже базовые символы.
- Пользователи, которым важна поддержка Unicode, должны тщательно выбирать терминал, так как не все эмуляторы поддерживают Unicode.
- Поддержка Unicode в терминалах может варьироваться от полной поддержки до полного отсутствия поддержки, что делает выбор сложным для пользователей, которым важна поддержка Unicode.
Zig's New Async I/O 🔥 Горячее
Zig представил новую асинхронную систему ввода-вывода, которая войдет в версию 0.16.0 через 3-4 месяца. Новый интерфейс std.Io позволяет писать асинхронный код с помощью ключевых слов async и await, декопируя вызов функции от ее возврата. Как и аллокаторы, std.Io настраивается один раз в main() и передается через приложение. В примерах показана эволюция от простого синхронного кода до полноценного асинхронного, где операции могут выполняться параллельно, сокращая реальное время выполнения.
Система включает реализацию на основе потоков (std.Io.Threaded), которая позволяет выполнять две односекундные операции за одну секунду реального времени. Примеры демонстрируют обработку ошибок в асинхронном контексте - при возникновении ошибки в одной из задач, другие продолжают выполняться. Новый подход делает код более выразительным и эффективным, позволяя Zig-приложениям лучше использовать современные возможности операционных систем.
Комментарии (112)
- Zig's async model is a radical departure from traditional async/await, emphasizing explicit I/O objects and no hidden control flow, but it has sparked debate on whether this is the right direction for the language.
- The discussion revealed that the lack of a standard async runtime and the decision to make the async/IO interface a public API has raised concerns about ecosystem fragmentation and the burden on library authors.
- Participants questioned whether the new model truly solves the "function color" problem or merely shifts it to a different place, and whether it will be able to scale to the ecosystem.
- The debate also touched on the risk of fragmentation if the community fails to converge on a de-facto standard library for async I/O, and the potential for a "left-pad" moment if the ecosystem becomes too fragmented.
- Some expressed concern that the lack of a blessed standard library could lead to a situation where "every game ships its own copy of DirectX" in the form of vendored async implementations, which could be a barrier to adoption.
How I turned Zig into my favorite language to write network programs in 🔥 Горячее
Автор изначально не интересовался Zig, считая его нишевым языком для аудиопрограмм, но решил переписать индекс AcoustID на Zig как возможность изучить новый язык. Результат превзошёл ожидания — новая версия оказалась быстрее и масштабируемее, чем предыдущая на C++. Однако при добавлении серверного интерфейса возникли сложности с сетевыми возможностями Zig, что привело автора к созданию библиотеки Zio — асинхронной I/O и библиотеки для конкурентности в стиле Go.
Zio реализует стековые корутины с фиксированным размером стека, поддерживает асинхронную сетевую и файловую I/O, примитивы синхронизации и каналы в стиле Go. Главная особенность — контекстный переключение практически бесплатен, сравним с вызовом функции. В однопоточном режиме Zio обгоняет все протестированные фреймворки, включая Go и Rust Tokio. Интересно, что благодаря стандартным интерфейсам reader/writer, внешние библиотеки могут использоваться без модификаций, даже не зная, что работают внутри Zio.
Комментарии (116)
- Обсуждение показало, что Zig не имеет встроенной поддержки async/await, а вместо этого используется библиотечный код, что вызывает вопросы о том, как это скажется на производительности и удобстве использования.
- Участники обсуждения также отметили, что в отличии от Go, где стек горутин растет по мере необходимости, в Zig фиксированный размер стека может ограничить количество одновременно работающих сопрограмм.
- Участники обсуждения также отметили, что в отличии от Go, где стек горутин растет по мере необходимости, в Zig фиксированный размер стека может ограничить количество одновременно работающих сопрограмм.
- Участники обсуждения также отметили, что в отличии от Go, где стек горутин растет по мере необходимости, в Zig фиксированный размер стека может ограничить количество одновременно работающих сопрограмм.
- Участники обсуждения также отметили, что в отличии от Go, где стек горутин растет по мере необходимости, в Zig фиксированный размер стека может ограничить количество одновременно работающих сопрограмм.
Synadia and TigerBeetle Commit $512k USD to the Zig Software Foundation 🔥 Горячее
Synadia и TigerBeetle совместно выделили $512,000 на поддержку Zig Software Foundation в течение двух лет. Synadia, создатель NATS.io, помогает крупным предприятиям проектировать и масштабировать архитектуры в облаке и на периферии, обслуживая клиентов в финансовой сфере, электронной коммерции, гейминге и промышленном IoT. TigerBeetle, финансовая база данных, разработанная на Zig с философией "TigerStyle", подчеркивает правильность, ясность и надежность.
Основатель Synadia Дерек Коллисон отметил, что Zig переопределяет возможности современного системного программирования благодаря своему подходу к контролю, производительности и простоте. Основатель TigerBeetle Йоран Дирк Гриф выразил уверенность, что Zig сыграет основополагающую роль в следующем поколении надежных распределенных систем. Обе компании разделяют видение предсказуемого, простого и заслуживающего доверия программного обеспечения, поддерживая Эндрю Келли и весь Zig-сообщество.
Комментарии (104)
- Оценивали Rust, Zig и Ada/SPARK для критически важного ПО; Rust имеет поддержку корпорации и сообщества, но не применяется в кибер-физических системах.
- TigerBeetle получил $512k в течение 2 лет от Synadia и TigerBeetle, что вызвало вопросы о стратегии финансирования и приоритете языков.
- Обсуждение вылилось в обмен любезностями и техническими деталями, включая предположения о переходе на Zig и оставлении Rust без должной поддержки.
Zig builds are getting faster 🔥 Горячее 💬 Длинная дискуссия
Компиляция Zig становится значительно быстрее благодаря многолетней работе над оптимизацией компилятора. Например, сборка скрипта build.zig в версии 0.15 заняла всего 1,7 секунды против 7,2 секунд в версии 0.14. Полная сборка проекта Ghostty без кеша сократилась с 41 до 32 секунд, даже с использованием LLVM.
Особенно впечатляет скорость инкрементных сборок: пересборка библиотеки libghostty-vt после изменения одной строки теперь занимает менее секунды (975 мс против 2,9 секунд ранее). Это уже ощутимо ускоряет рабочий процесс, а в будущем, с отказом от LLVM и внедрением инкрементной компиляции, результаты станут ещё лучше — ожидаются миллисекундные задержки.
Комментарии (190)
- LLVM рассматривается как ловушка из-за сложности тонкой настройки финальных оптимизаций и линковки, несмотря на преимущества в скорости начальной разработки и поддержке платформ. Cranelift и другие бэкенды могут стать альтернативой.
- Zig фокусируется на скорости компиляции для разработки, используя собственный бэкенд для debug-сборок (x86_64) и LLVM для релизов. Есть баги, но инструментарий ценится за простую кросс-компиляцию и статическую линковку.
- Быстрая компиляция (TCC, Go, Vlang) важна для итеративной разработки, но trade-off с оптимизацией кода неизбежен. Интерпретаторы или JIT-компиляция (Julia) предлагают альтернативы для интерактивности.
- Интеграция Zig с системами сборки (Bazel) возможна через правила, но Turing-полные скрипты сборки могут усложнить кеширование. Библиотеки часто обходятся без кастомных скриптов.
- Поддержка платформ (OpenBSD) требует доработки низкоуровневого IO (kqueue). Статическая линковка зависимостей в Zig упрощает деплой, но динамические библиотеки (libc, GUI) остаются.
TigerBeetle is a most interesting database 🔥 Горячее 💬 Длинная дискуссия
TigerBeetle — это финансовый транзакционный движок, построенный на принципах, противоположных общепринятым: медленная разработка кода, детерминированное симуляционное тестирование и нулевые зависимости. Вместо SQL он использует примитивы дебета и кредита, что соответствует изначальной цели транзакционных систем — обеспечению бизнес-операций, как описал ещё Джим Грей в 1985 году.
Традиционные SQL-базы требуют 10–20 запросов для обработки одной финансовой транзакции, создавая узкие места, особенно при работе с «горячими» счетами. TigerBeetle, написанный на Zig, предлагает распределённую архитектуру по умолчанию, статическое выделение памяти и assertions в продакшене. Это ответ на растущие потребности в мгновенных платежах и реальном биллинге, где скорость и надёжность критичны.
Комментарии (170)
- Участники обсуждают технические особенности TigerBeetle, включая его специализацию на финансовых операциях, детерминированное тестирование и минималистичный подход к зависимостям.
- Высказываются критические замечания: отсутствие поддержки многопоточности для масштабирования, проблемы с аутентификацией и совместимостью с облачными платформами, такими как Cloudflare Workers.
- Поднимается вопрос о потенциальной предвзятости статьи, так как её автор является инвестором проекта.
- Отмечается, что традиционные SQL-базы данных по-прежнему эффективно справляются с большинством задач, несмотря на возраст.
- Обсуждаются возможные аналоги TigerBeetle, такие как FoundationDB, и его применимость за пределами финансового сектора.
Systems Programming with Zig
Zig — это современный язык системного программирования, который предлагает альтернативу C и C++ с акцентом на безопасность, производительность и простоту. Он исключает неопределённое поведение благодаря строгой проверке типов и управлению памятью без сборщика мусора, что делает его особенно привлекательным для низкоуровневых задач. Zig также предоставляет мощные инструменты для метапрограммирования и кроссплатформенной компиляции.
Одной из ключевых особенностей Zig является его минималистичный дизайн и предсказуемость выполнения, что снижает сложность отладки и поддержки кода. Язык активно развивается и набирает популярность в сообществе за счёт своей прозрачности и эффективности. Практический вывод: Zig может стать отличным выбором для проектов, где критичны контроль над памятью и производительность.
Комментарии (90)
- Критики выражают сомнения в целесообразности использования Zig для крупных проектов из-за отсутствия гарантий памяти, как в Rust или Swift, и нестабильности языка до версии 1.0.
- Сторонники Zig отмечают его сильные стороны: простоту, явный контроль над выделением памяти, отличную совместимость с C и возможность писать код без использования кучи.
- Обсуждаются практические примеры успешного использования Zig в реальных проектах (Tiger Beetle, Ghostty), несмотря на нестабильность.
- Поднимается вопрос о своевременности выхода книги по языку, который всё ещё активно меняется, что может быстро сделать издание устаревшим.
- Утверждается, что безопасность памяти — это спектр, а не бинарный выбор, и что простота Zig может снижать количество логических ошибок в целом.
Libghostty is coming 🔥 Горячее 💬 Длинная дискуссия
Разработчик Mitchell Hashimoto анонсировал libghostty — библиотеку для встраивания полнофункционального терминала в любые приложения. Первым компонентом станет libghostty-vt: легковесная библиотека без зависимостей (включая libc) для парсинга терминальных последовательностей и управления состоянием терминала. Она извлечена из ядра Ghostty и предлагает оптимизированную обработку Unicode, поддержку SIMD и совместимость с продвинутыми протоколами вроде Kitty Graphics.
Проблема в том, что многие проекты (редакторы, веб-консоли, хостинги) реализуют эмуляцию терминала с нуля, часто с ошибками и неполной функциональностью. Libghostty-vt устраняет эту избыточность, предоставляя единое корректное и быстрое решение. Библиотека будет портирована на macOS, Linux, Windows, embedded-устройства и WASM, что шире, чем охват самого Ghostty.
Комментарии (239)
- Пользователи высоко оценивают Ghostty за его производительность, минималистичный дизайн и поддержку Zig, но отмечают отсутствие некоторых ключевых функций, таких как поиск (Cmd+F) и проблемы с рендерингом шрифтов.
- Многие выражают восхищение разработчиком Mitchell Hashimoto, его предыдущими проектами (Vagrant) и его подходом к созданию простых и эффективных систем.
- Анонс библиотеки libghostty вызвал интерес для использования в embedded-сценариях (игры, кастомные приложения, веб-терминалы) и как потенциальная замена существующим библиотекам.
- Некоторые пользователи столкнулись с проблемами совместимости, особенно с tmux и графическими протоколами, что мешает им полностью перейти с iTerm2 или других терминалов.
- Обсуждаются технические детали, такие как лицензирование (MIT vs LGPL), поддержка Unicode и сравнение с другими терминалами (Kitty, Alacritty, WezTerm).
Zig feels more practical than Rust for real-world CLI tools 💬 Длинная дискуссия
Zig предлагает более простой подход к созданию CLI-инструментов по сравнению с Rust, особенно когда речь идёт о работе с памятью. В Rust строгий borrow checker предотвращает ошибки на этапе компиляции, но часто вынуждает переписывать код под его требования, усложняя разработку. Например, при попытке добавить новую запись в список, одновременно удерживая ссылки на существующие, компилятор Rust блокирует действие из-за конфликта владения и заимствования.
В Zig же разработчик напрямую управляет памятью через аллокаторы, используя указатели и мутацию без сложных правил времён жизни. Это требует дисциплины, но даёт больше гибкости и скорости написания кода. Для CLI-инструментов, где производительность и простота часто важнее абсолютной безопасности памяти, Zig оказывается практичнее. Безопасность — это не только отсутствие ошибок памяти, но и читаемость, скорость разработки и соответствие задаче.
Комментарии (209)
- Обсуждение затрагивает проблемы безопасности в C, связанные с ручным управлением памятью, и ироничные комментарии по этому поводу.
- Пользователи делятся мнениями о современных языках (Nim, Odin, V, D, Zig), отмечая их преимущества, такие как интероперабельность с C и гибкость в управлении памятью.
- Уточняется функциональность Zig: он не компилируется в C, но имеет инструмент для трансляции C-кода в Zig, при этом компилируясь напрямую в машинный код.
- В обсуждении присутствует юмористический тон относительно утверждения, что разработчики не являются идиотами.
Zig got a new ELF linker and it's fast
jacobly0 предлагает полностью переписать линкер Zig с нуля, создав Elf2 вместо текущей реализации. Основная цель — повысить производительность, уменьшить потребление памяти и улучшить поддержку различных форматов объектных файлов. Новая архитектура позволит эффективнее обрабатывать символы, секции и релокации, избегая проблем существующего кода.
Ключевые улучшения включают параллельную обработку, лучшую диагностику ошибок и оптимизацию для больших проектов. Это может значительно ускорить сборку в экосистеме Zig и упростить дальнейшее расширение. Практический вывод: переписывание устаревших компонентов иногда необходимо для долгосрочной масштабируемости.
Комментарии (24)
- Участники высоко оценивают Zig как компилятор для C/C++ и инструмент кросс-компиляции за его простоту и самодостаточность.
- Отмечается мощная вертикально интегрированная система сборки Zig, включающая линкер и бэкенды генерации кода, что открывает возможности для оптимизаций.
- Обсуждаются ограничения использования линкера Zig (elf2) и самого компилятора вне экосистемы Zig, а также отсутствие неструктурированного goto.
- Некоторые пользователи выражают смешанные чувства: язык делает многое правильно, но отдельные изменения и особенности вызывают сомнения.
- Упоминается книга "Linkers and Loaders" и общее оживление в области разработки линкеров (ренессанс).
Is Zig's new writer unsafe?
Новый интерфейс std.Io.Reader в Zig может приводить к неопределённому поведению при использовании с буфером произвольного размера. Например, при передаче ридера из zstd-декомпрессора в функцию вывода с буфером 64 байта код либо аварийно завершается в режиме отладки, либо зацикливается в релизе. Проблема в том, что некоторые ридеры требуют конкретного размера буфера у писателя, но это требование не всегда очевидно или документировано.
Ситуация усугубляется тем, что сбой может зависеть от входных данных: с одними данными код работает, с другими — нет. Это создаёт риски для библиотек, где тип ридера неизвестен заранее, например, при обработке HTTP-заголовков. Автор спрашивает, не ошибся ли он, но если нет — это серьёзный изъян в дизайне API.
Комментарии (112)
- Обсуждается потенциальная проблема безопасности или баг в Zig, но участники склоняются к тому, что это скорее единичная ошибка, а не системная уязвимость.
- Участники дискутируют о ценностном предложении языка Zig, описывая его как современную альтернативу C с лучшей эргономикой, компиляцией во время выполнения (comptime), явным управлением памятью и меньшим количеством неопределённого поведения.
- Критикуется реакция создателя Zig, Эндрю Келли, на конструктивную критику, которую некоторые участники сочли резкой и недружелюбной.
- Zig позиционируется как мощный инструмент для низкоуровневого программирования с ультранизкой задержкой (например, для HFT или игр), где безопасность не является приоритетом, в противовес Rust.
- В качестве альтернатив для модернизации C++ упоминаются другие языки, такие как Carbon.
Show HN: Zedis – A Redis clone I'm writing in Zig
Реализация Redis на языке Zig, демонстрирующая потенциал этого молодого языка для системного программирования. Проект повторяет базовые функции популярной базы данных, включая работу с ключами, строками, списками и хешами, используя эффективность и безопасность Zig.
Особый интерес вызывает использование статической типизации и управления памятью без сборщика мусора, что может привести к повышению производительности и снижению задержек. Это пример того, как современные низкоуровневые языки могут конкурировать с классическими решениями.
Комментарии (92)
- Обсуждаются альтернативы Redis, такие как kvrocks, Garnet и Redka, с поддержкой хранения данных на диске и работой в условиях ограниченной памяти.
- Участники дискутируют о стабильности языка Zig для реальных проектов, отмечая частые изменения в стандартной библиотеке и отсутствие версии 1.0.
- Поднимается вопрос о названии проекта "RiiZ" и возможном нарушении торговой марки Redis из-за схожести имен.
- Отмечается, что проект является учебным для изучения Zig, а не коммерческим продуктом, и пока не поддерживает все функции Redis (например, аутентификацию, поиск ключей).
- Обсуждаются технические детали реализации памяти и деструкторов в Zig, а также возможность использования LLM для генерации кода на этом языке.
Show HN: I wrote an OS in 1000 lines of Zig
Разработчик создал операционную систему всего в 1000 строк кода на языке Zig. Проект демонстрирует минималистичный подход к построению ОС, включая базовые функции: управление процессами, памятью и простой интерфейс. Zig выбран за его безопасность, производительность и низкоуровневые возможности.
Такой лаконичный код позволяет легко изучать и модифицировать систему, что полезно для образовательных целей. Проект подчёркивает, что сложные системы можно создавать без избыточного кода, используя современные языки программирования.
Комментарии (20)
- Создание минималистичной ОС на Zig в рамках 1000 строк кода с базовыми функциями: загрузка, управление памятью, планирование задач и вывод текста.
- Критика и вопросы по реализации: отсутствие консольного вывода, несоответствие README, проблемы сборки на разных платформах.
- Обсуждение технических деталей: формат выходных файлов, поддержка архитектур (RISC-V, ARM), использование библиотек.
- Рекомендации по улучшению: исправить .gitignore, уточнить версии компилятора, дополнить документацию.
- Ссылки на аналогичные проекты и запрос на более глубокий анализ целей проекта и опыта использования Zig.
Writing an operating system kernel from scratch 🔥 Горячее
- Ядро ОС написано на Zig для RISC-V, одноядерное, с вытесняющей многозадачностью и системными вызовами.
- Unikernel: приложения линкуются с ядром в один бинарник.
- OpenSBI обслуживает M-режим; ядро работает в S-режиме, потоки — в U.
- Потоки статические, бесконечные функции; переключение по таймеру каждые 2 мс.
- Контекст сохраняется на стеке прерываний; ядро и пользователь разделены.
- GitHub: popovicu/zig-time-sharing-kernel
Комментарии (64)
- Участники делятся опытом создания минимальных ОС на RISC-V и Zig: кто-то перевёл «ОС в 1000 строк» на Zig, кто-то пишет с нуля.
- Все сходятся: RISC-V проще x86, нет легаси-багажа, документация и эмуляторы доступны.
- Железо не обязательно: достаточно QEMU; если нужна «реалка» — Milk-V Duo S за $10 или Pico 2.
- Миникernel — хороший способ выучить архитектуру и Forth; «не изобретай крипту для продакшена» не отменяет экспериментов.
- В споре о «кто важнее» вспомнили: Линус начинал как хобби, а Столлман уже с 1984 года готовил инфраструктуру GNU.
Writing an operating system kernel from scratch – RISC-V/OpenSBI/Zig
Разработка ядра операционной системы с нуля
Недавно я реализовал минимальное ядро ОС с разделением времени для RISC-V. В этой статье расскажу о деталях работы прототипа. Материал предназначен для всех, кто интересуется низкоуровневым ПО, драйверами, системными вызовами, и особенно полезен студентам, изучающим системное ПО и архитектуру компьютеров.
Это переработанная версия учебного проекта по операционным системам, но с фокусом на современные инструменты и архитектуру RISC-V. RISC-V — перспективная технология, которая проще для понимания по сравнению с другими архитектурами, оставаясь популярным выбором для новых систем.
Вместо традиционного C я использовал Zig, что упрощает воспроизведение эксперимента благодаря простой настройке и отсутствию необходимости установки дополнительных инструментов для кросс-компиляции под RISC-V.
Репозиторий и рекомендации
Исходный код доступен на GitHub. Перед изучением рекомендуется ознакомиться с основами программирования на RISC-V без ОС, процессом загрузки через SBI и обработкой прерываний.
Архитектура
Мы разрабатываем унике́рнел (unikernel), где приложение и ядро объединены в один исполняемый файл. Это исключает необходимость отдельной загрузки пользовательского кода во время выполнения.
В основе стека лежит слой SBI (OpenSBI), который управляет выводом на консоль и таймером. RISC-V использует уровни привилегий: M-режим (машинный), S-режим (супервизора) и U-режим (пользовательский). Наше ядро работает в S-режиме.
Цели ядра
- Статическое определение потоков (без динамического создания).
- Потоки выполняются в пользовательском режиме и могут делать системные вызовы к ядру.
- Время распределяется между потоками с помощью таймера, который прерывает выполнение каждые несколько миллисекунд.
- Разработка ведётся для одноядерной системы.
Виртуализация и потоки
Перед реализацией важно понять, что такое поток. В среде с разделением времени потоки позволяют эффективно использовать ресурсы системы.
Комментарии (3)
- Автор переписал классическое упражнение по созданию минимального ядра ОС с разделением времени для управления пользовательскими потоками.
- Целью был эксперимент на специфической платформе RISC-V в сочетании с OpenSBI.
- Для реализации был использован язык программирования Zig вместо традиционного C.
- Автор отмечает, что подход можно легко повторить на C или Rust.
- Участник обсуждения предположил, что эта тема уже публиковалась неделей ранее.
- Другой участник уточнил, что оригинальный пост был два дня назад на Hacker News.
- Было отмечено, что текущий пост, хотя и от первоначального автора, изначально не получил отклика и был повторно запущен через «пул второго шанса» с измененными временными метками.
A Web Framework for Zig
Jetzig — веб-фреймворк на Zig, MIT-лицензия.
Маршруты по файлам, REST из коробки.
Шаблоны Zmpl: лейауты, partials, статика на этапе сборки.
JSON-ответ по умолчанию.
Движок http.zig = высокая скорость.
CLI создаёт проекты и компоненты.
Цепочка middleware, встроенная поддержка htmx.
Куки, сессии, заголовки — без кода.
ORM JetQuery для баз данных.
Сообщество в Discord, исходники на GitHub.
Комментарии (16)
- Jetzig — новый Zig-фреймворк для веба: single-бинарник, статическая типизация, маршруты через структуры, напоминает Django.
- Название играет по-немецки: «jetzig» ≈ «сейчас-вроде» (now-ish), как у Zeit/Now.sh.
- Под капотом http.zig, значит пока только HTTP/1.1; RESTful на словах, но по факту JSON-RPC.
- Видео-вводилка уже есть, комьюнити хвалит «правильные» решенийки, но докопались до баннера куки на localhost.
- JetQuery даёт compile-time безопасность имён полей — если переименуете член структуры, код не соберётся.
Behind the scenes of Bun Install 🔥 Горячее
Как устроен bun install
- Один бинарник — весь менеджер зависимостей живёт внутри Bun, нет внешних вызовов к npm, yarn, node-gyp.
- Сишный движок — парсинг package.json, yarn.lock, node_modules происходит на Zig, без JS-оверхеда.
- HTTP-пул + кэш — 50–100 параллельных потоков, кэш на диске + SQLite-индекс, повторный install — <100 мс.
- Symlink-ферма — модули не копируются, а hard-link’ются из глобального кэша; экономия 70 % диска.
- Муравьиный алгоритм — сначала скачиваются «листья» дерева зависимостей, потом родители; сеть греется максимально.
- Платформенные пакеты — если в lock-файле есть запись под Linux, macOS и Windows, скачиваются сразу три архива и раскладываются в
node_modules/.cache, при запуске выбирается нужный. - postinstall без shell — скрипты запускаются встроенным JS-движком, нет overhead’а на spawn bash/cmd.
- Проверка целостности — каждый tarball сверяется по SHA256 из lock-файла, кэш защищён от подмены.
- Мониторинг прогресса — терминал обновляется раз в 16 мс, рисуется ASCII-полоса и счётчик «пакетов/сек».
- Фоллбек к npm — если пакет не найден в официальном реестре, Bun автоматом лезет в npm и кладёт tarball в кэш, пользователь не замечает разницы.
Комментарии (134)
- Пользователи обсуждают статью о внутреннем устройстве и производительности менеджера пакетов Bun.
- Многие хвалят скорость и простоту Bun, но отмечают проблемы совместимости с Node.js и стабильностью.
- Часть комментаторов сомневается в практической пользе высокой скорости установки пакетов и считает переход с Node.js рискованным.
- Упоминаются альтернативы — Deno, pnpm, npm — и сравнение с ними по скорости и надёжности.
- Некоторые считают, что Bun не предлагает «убийственных» фич, чтобы оправдать переход с зрелой экосистемы Node.js.
Hitting Peak File IO Performance with Zig
Как выжать максимум из файлового IO в Linux на Zig + io_uring
Тест
- Железо: Ubuntu 24.04, 6.14, NVMe, 32 ядер, 756 ГБ ОЗУ (не влияет,
direct_io). - Параметры: 512 КБ блок, очередь 64, 16 ГБ файл, один поток.
Результаты
| fio | Zig | |
|---|---|---|
| write | 4.08 ГБ/с | 3.80 ГБ/с |
| read | 7.33 ГБ/с | 7.00 ГБ/с |
Zig на 5–7 % медленнее fio, но близко к пределу SSD.
Ключевые фишки реализации
- Полл-режим (
IOPOLL) +nvme.poll_queues=16→ прерывания не нужны. - Два экземпляра io_uring: один с
IOPOLL(только read/write), второй – для остального. - Зарегистрированные буферы: память выделяется заранее, пользователь получает/возвращает готовые блоки.
- Выравнивание:
- чтение – внутренняя «перехватка» невыравненных запросов;
- запись – пользователь сам выравнивает, иначе лишние read-modify-write.
- Без слияния IO внутри библиотеки – проще и гибче на уровне приложения.
Код: steelcake/csio
Комментарии (11)
- Пользователи указывают, что 7 ГБ/с при 512 КБ блоках — это всего ~14 000 IOPS (~70 мкс/IO), и требуется лишь 1 предзагрузка для полной полосы.
- Напоминают, что Zig 0.15.1 всё ещё меняет IO-API, поэтому версию нужно явно указывать в посте.
- Рекомендуют проверить/увеличить логический блок NVMe до 4 КБ через nvme-format вместо хардкода ALIGN=512.
- Разница 4,08 ГБ/с (fio) и 3,80 ГБ/с (Zig) объясняется путаницей GiB ↔ GB.
- Для io_uring важно использовать registered fds — дают заметный прирост.
- Интересуются, как будет работать тот же код на FreeBSD AIO.
- Предлагают вместо «овераллокации» брать выровненную память через page-аллокатор.
Zig Software Foundation 2025 Financial Report and Fundraiser
ZSF нужны деньги!
Сбор средств 2025: 28 дней осталось, талисманы пока на нуле.
Пожертвовать
Расходы 2024 (итого $520 749)
- Контракторы – $306 362 (92 % бюджета, $60/час).
- Сотрудники – $154 263 (один Andrew Kelley).
- Бухгалтерия – $18 464 (Strada Financial Group).
- CI и сайт – $14 987 (железо + Hetzner).
- Налоги – $13 089.
- Поездки – $6 956 (Италия, Германия).
- Спонсорство – $5 846 (musl, mingw-w64 и др.).
- Банковские комиссии – $782.
Что сделано в 2024
- Выпущены Zig 0.13.0 и 0.14.0 (расширены цели, язык, стандартная библиотека, билд-система).
- 0.14.1 – только фиксы.
Доходы и тренд
- Пожертвования постепенно снижаются.
- Пик – половина $300 000 от Mitchell Hashimoto.
- Вторую половину нужно заменить, чтобы не уйти в минус.
Рост нагрузки
- Активность пользователей и количество GitHub-issues растут быстрее, чем закрываются.
Комментарии (44)
- Участники хвалят Zig Foundation за прозрачность отчёта и модель оплаты контрибьюторов, но удивлены отсутствием крупных корпоративных спонсоров.
- Основатель получает $150 тыс. после налогов из пожертвований; многие считают это оправданным, но рекордным для GitHub Sponsors.
- Вопросы вызвали статья расходов на налоги с зарплат и $15 тыс. на CI/сайт: одни видят расточительство, другие — норму для такой инфраструктуры.
- Представитель Zig подтвердил открытость к корпоративным спонсорам без уступки мест в совете.
My Foray into Vlang
V как Go с шоколадкой
Go — это ваниль: просто, быстро, без фанатизма. V же — «ваниль++»: тот же вкус, но сверху посыпка из фич.
Карты
langs := {"elixir": {"score": 100}}
score := langs["elixir"]["score"] or { -1 }
Фиксированные типы, or {} вместо if err != nil, spread-оператор ... для слияния.
Структуры
struct Language {
pub mut:
score int = -1
name string @[required]
}
Методы можно вешать прямо на массивы, поля можно помечать @[required], дефолты и флаги CLI задаются в одном месте.
WithOption
fn new_server(opts ServerOptions) ! { ... }
Встроенный «функциональный» паттерн: new_server(port: 8080, debug: true).
Enum и лямбды
Enum’ы есть, лямбды короткие: nums.filter(it % 2 == 0).
Подводные камни
net.httpпока не дотягивает до Go.veb(веб-фреймворк) сырой.- Сборка сложнее: нужен
vи C-компилятор. - Параллелизм есть, но экосистема молода.
Итог
V — это Go с синтаксическим сахаром и парой острых углов. Для экспериментов — огонь, для продакшена — пока нет.
Комментарии (30)
- Участники спорят, действительно ли V лучше Go: одни отмечают быструю компиляцию и «красивые» фичи, другие — нестабильность компилятора и отсутствие надёжности.
- Поддерживающие Go указывают на его зрелость, стабильность GC, удобство кросс-компиляции и отказ от «лишнего».
- Сторонники V хвалят синтаксис (const по умолчанию, sum types, простой С-интерфейс), но признают, что язык пока «сырой».
- Некоторые считают V «предупреждением» о том, почему Go часто говорит «нет» новым возможностям.
- Есть мнение, что ни Go, ни V не решают задачу «лёгкого C для приложений»; предлагают смотреть на Zig или Free Pascal.
Fenster: Most minimal cross-platform GUI library
fenster — сверхкомпактная кроссплатформенная GUI-библиотека.
-
Особенности:
- Окно, пиксельный буфер, ввод с клавиатуры/мыши.
- Один
.hфайл, ~400 LOC, зависимости: X11 (Linux), Cocoa (macOS), Win32 (Windows). - Поддержка C/C++, Zig, Odin, Rust, Go, JS (WASM), C#, Swift, Pascal, Nim, Lua, Python, Ruby, OCaml, Fortran.
-
Быстрый старт (C):
#define FENSTER_IMPL
#include "fenster.h"
int main() {
struct fenster f = {.width = 320, .height = 240, .title = "demo"};
uint32_t buf[320*240];
for (fenster_open(&f); fenster_loop(&f) == 0; ) {
// рисуем
fenster_sync(&f, buf);
}
return 0;
}
-
Сборка:
cc demo.c -o demo(Linux:-lX11, macOS:-framework Cocoa, Windows: без флагов). -
API (C):
fenster_open,fenster_close,fenster_loop,fenster_sync.- Поля:
width,height,title,keys[64],mouse.
-
Лицензия: MIT.
Комментарии (31)
- Fenster — это минимальная C-библиотека, создающая окно с пиксельным буфером, а не полноценный GUI с кнопками и меню.
- Участники отмечают отсутствие скриншотов и просят добавить их в README.
- Название «Fenster» переводится как «окно» на немецком, африкаанс, шведском и других языках.
- Некоторые считают polling-цикл ошибкой, другие считают его допустимым для такой простой задачи.
- В блог-посте нашли опечатку в sizeof и ограничение кода 8-битными цветами.
- Проект вызывает интерес для визуализации данных и как лёгкая альтернатива raylib.
I'm too dumb for Zig's new IO interface 💬 Длинная дискуссия
Zig 0.15 сменил IO: std.Io.Reader и std.Io.Writer.
Старый способ тормозил и путался из-за anytype.
Подключаемся к www.openmymind.net:443:
const std = @import("std");
pub fn main() !void {
var gpa = std.heap.DebugAllocator(.{}).init;
defer gpa.deinit();
const a = gpa.allocator();
const s = try std.net.tcpConnectToHost(a, "www.openmymind.net", 443);
defer s.close();
var wbuf: [std.crypto.tls.max_ciphertext_record_len]u8 = undefined;
var rbuf: [std.crypto.tls.max_ciphertext_record_len]u8 = undefined;
var w = s.writer(&wbuf);
var r = s.reader(&rbuf);
var bundle = std.crypto.Certificate.Bundle{};
try bundle.rescan(a);
defer bundle.deinit(a);
var tls_buf: [std.crypto.tls.max_ciphertext_record_len]u8 = undefined;
var tls = try std.crypto.tls.Client.init(
r.interface(),
&w.interface,
.{
.ca = .{ .bundle = bundle },
.host = .{ .explicit = "www.openmymind.net" },
.read_buffer = &.{},
.write_buffer = &tls_buf,
},
);
defer tls.end() catch {};
try tls.writer.writeAll("GET / HTTP/1.1\r\n\r\n");
var out: [1024]u8 = undefined;
var fw = std.Io.Writer.fixed(&out);
const n = try tls.reader.stream(&fw, .limited(out.len));
std.debug.print("read: {s}\n", .{out[0..n]});
}
Ключевые моменты
stream.reader()иwriter()требуют буфер.- Чтобы передать их в
tls.Client, нужно.interface()и&interface. tls.Client.initобязательно проситca,host,read_buffer,write_buffer.- Чтение ответа:
tls.reader.streamвstd.Io.Writer.
Комментарии (161)
- Автору пришлось вручную вызывать flush у двух обёрток и разбираться с тем, что первое чтение всегда возвращает 0.
- Основная жалоба — отсутствие документации и примеров; сообщество отвечает «читай исходники», но участники признают, что API ещё нестабилен.
- Некоторые считают новый I/O-интерфейс элегантным, но сложным даже для «Hello, world!»; другие предпочитают прямое использование системных API.
- Zig позиционируется как язык системного программирования, близкий к C, с преимуществами вроде discriminated unions и comptime, но сопровождается постоянными breaking changes.
Why Nim? 💬 Длинная дискуссия
—
Комментарии (175)
- Участники жалеют, что выразительные языки с нативной компиляцией и автоматическим управлением памятью (Nim, D) не стали массовыми.
- Любители Nim хвалят его скорость, надёжность компилятора и эргономику, но жалуются на малую экосистему, устаревшую документацию и сложность кросс-компиляции.
- Скептики считают, что «выразительность» и макросы делают язык нишевым, требуют больше знаний и усложняют чтение чужого кода.
- Многие отметили, что успех языка определяют не фичи, а деньги, стандартная библиотека, тулинг и сообщество; Rust выиграл именно этим.
- Часть разработчиков ушла из Nim в Rust, Go или Zig из-за зрелости инструментов и богатой экосистемы, но продолжают следить за Nim и надеются на его рост.
We rewrote the Ghostty GTK application 🔥 Горячее 💬 Длинная дискуссия
Ghostty GTK-часть переписана с нуля
Проект завершён: Linux/BSD-версия теперь полностью использует GObject из Zig и проверена Valgrind.
Что изменилось
- Zig-структуры обёрнуты в GObject; память управляется счётчиками ссылок.
- При обновлении конфига старый объект освобождается автоматически, когда исчезают ссылки.
- Появились сигналы, свойства, действия GTK и современные UI-файлы Blueprint.
- Новые виджеты добавляются быстрее (анимированная рамка, вкладки в заголовке и т.д.).
Valgrind Каждый коммит прогонялся под Valgrind.
- Потребовался большой suppression-файл (в основном GTK/драйверы).
- Найдены: утечка и неопределённое обращение в Zig-коде, ошибка
WeakRefв GTK, которые иначе вызывали редкие краши.
Комментарии (194)
- Ghostty переписывает GUI на GTK/Zig, столкнувшись с проблемами GObject и управления памятью.
- Участники обсуждают, что GTK навязывает свою ООП-модель и счётчики ссылок, что сложно сочетать с Zig/Rust.
- Некоторые считают GTK не «родной» на Linux и предлагают Vala, Qt или собственный UI.
- Пользователи жалуются на баги прокрутки, копирования, nano и отсутствие поиска.
- Автор признаёт выбор GTK компромиссом ради кроссплатформенности и «родного» вида.
Faster substring search with SIMD in Zig
SIMD-поиск подстроки в Zig
Автор реализовал алгоритм, который на 60 % быстрее std.mem.indexOf.
Идея: сравниваем 32-байтовые блоки текста с первым и последним символом искомого слова, используя AVX2.
- Берём первый и последний байт
needle(first,last). - Загружаем 32 байта
haystackв векторBlock = @Vector(32, u8). - Создаём маски совпадений:
const eq_first = first == block; const eq_last = last == block_shifted; const mask = @bitCast(eq_first & eq_last); - Для каждого установленного бита проверяем полное совпадение подстроки.
- Хвост обрабатываем обычным
indexOf.
Код (сокращённо):
const Block = @Vector(32, u8);
const first = @splat(needle[0]);
const last = @splat(needle[k-1]);
while (i + k + 32 <= n) : (i += 32) {
const f = haystack[i..][0..32].*;
const l = haystack[i+k-1..][0..32].*;
var mask: u32 = @bitCast((first == f) & (last == l));
while (mask != 0) {
const bit = @ctz(mask);
if (mem.eql(u8, haystack[i+bit+1..][0..k-1], needle[1..]))
return i + bit;
mask &= mask - 1;
}
}
return mem.indexOf(u8, haystack[i..], needle) orelse null;
Тест: поиск слова «newsletter» во всём «Моби Дике» (~1.2 МБ).
Сборка: zig build -Doptimize=ReleaseFast.
Комментарии (52)
- Подход с SIMD-ускорением поиска подстроки популярен, но в худшем случае остаётся квадратичным
O(m·n), поэтому нужен «откат» на линейный алгоритм (KMP/BM). - Участники отмечают, что большинство реализаций опираются на 10-летние AVX/NEON, игнорируя AVX-512, SVE и RVV, которые дают больший выигрыш, но пока редки на десктопах и в облаках.
- Zig пока не предоставляет прямых intrinsics, хотя LLVM-бекенд позволяет вызывать нужные инструкции; это тормозит портирование низкоуровневых оптимизаций.
- Есть идея дальнейшего SIMD-фильтра: проверять не только первый/последний байт иглы, но и второй/предпоследний и т.д., накладывая маски.
- Вопросы Unicode: алгоритм работает на байтах, поэтому для UTF-8/16 потребуется дополнительная обработка переменной длины кодов.
Zig's Lovely Syntax 💬 Длинная дискуссия
Zig выглядит почти как Rust, но делает синтаксис ещё приятнее за счёт более простой семантики и ряда изящных решений.
Числа
Литералы 92 всегда имеют тип comptime_int; при присваивании они неявно приводятся к нужному типу. Суффиксов нет.
Строки
Многострочные «сырые» строки пишутся через \\ в начале каждой строки; \ не экранируется, отступы не портятся, а лексер работает построчно.
Структуры
.{ .x = 1, .y = 2 } — запись поля через .x = совпадает с присваиванием, что позволяет грепом находить именно записи, а не чтения.
Типы
Все типы префиксные: u32, [3]u32, ?[3]u32, *const ?[3]u32. Разыменование постфиксное: ptr.*.
Идентификаторы
Синтаксис @"имя с пробелом" позволяет обходить ключевые слова и экспортировать любые имена.
Функции
fn add(x: i32, y: i32) i32 — без стрелки ->, так как лямбд нет, а возвращаемый тип всегда обязателен. pub fn main() void {}.
Переменные
const и var; часто используемое const короче, чем в Rust, но всё же длиннее Kotlin-овского val.
Комментарии (156)
- Обсуждение разделилось: кому-то синтаксис Zig кажется «прекрасным» минимализмом, другим — «шумным» и «капризным».
- Спор о порядке «имя: тип» vs «тип имя»: одни хотят видеть тип первым, другие — имя.
- Критика деталей: @-префиксы,
.{}, отсутствие лямбд, перенос строк,orelseбез пробела. - Плюсы: raw-строки Zig решают проблему отступов; обработка ошибок через
tryнравится многим. - Сравнения: Kotlin, C#, Go, Rust, D — каждый считает «своё» лучше.
- Итог: «красота» синтаксиса субъективна и во многом привычна; после практики Zig начинает нравиться.
Debian GNU/Hurd 2025 released
Debian GNU/Hurd 2025 — неофициальный релиз Debian, но официальный порт.
Основан на «sid» в момент выхода «Trixie».
- ISO: hurd-i386 | hurd-amd64
- Образы и инструкции: hurd-install
Архитектуры: i386, amd64; покрытие ~72 % архива Debian.
Новое
- 64-бит полностью готов, драйверы дисков через Rump (NetBSD).
- xattr по умолчанию для трансляторов; mmdebstrap из других ОС.
- Порт Rust, USB-диски и CD через Rump.
- SMP, xkb-раскладки, framebuffer, acpi, rtc, apic, hpet.
- Исправления irqs, nfsv3, libports, pipes и др.
Документация
Присоединяйтесь: contributing
Комментарии (107)
- Hurd — давний проект с микроядром Mach, фактически движимый одним человеком (Samuel Thibault), и сегодня выглядит скорее хобби-экспериментом, чем реальной альтернативой Linux.
- Участники обсуждают низкую поддержку железа, архаичную архитектуру и отсутствие прогресса: «ждать совершенства — значит никогда не стать готовым».
- Предлагаются новые микроядра (seL4, L4, Viengoos) и языки (Rust, Zig), но критика считает это погоней за хайпом.
- GUIX/Nix и GNU Shepherd упоминаются как более живые GNU-ориентированные проекты; GUIX уже умеет запускать Hurd в виртуалке.
- Итог: Hurd остаётся интересным музейным экспонатом и источником идей, но не готов к «повседневному» использованию.
Комментарии (89)
- Zig вызывает интерес благодаря мощному comptime и «inline else», позволяющим абстрагироваться без рантайм-оверхеда.
- Участники сравнивают его метапрограммирование с C, D и Rust, отмечая, что похожие идеи уже были, но Zig может сделать их популярнее.
- Главный упрек Zig — отсутствие гарантий memory- и data-race safety, из-за чего многие считают его неподходящим для многопоточного кода.
- «comptime unreachable» воспринимается как способ доказать компилятору недостижимость кода, а не как runtime-assert.
- Некоторые считают, что язык ещё нестабилен и экосистема незрела, поэтому широкое внедрение отложено.
A fast, growable array with stable pointers in C
Моя предыдущая статья о обобщённых структурах данных в C готовила почву к теме: структура, которая заменяет динамические массивы, даёт стабильные указатели и хорошо работает с аренными аллокаторами. Её переоткрывали много раз под разными именами: “levelwise-allocated pile” (2001), в Zig — Segmented List, частично похожая на C++ std::deque. Мне нравится название Per Vognsen — Segment Array.
Скачать мой однофайловый заголовок segment_array.h можно, подписавшись на рассылку.
Идея проста: фиксированный массив указателей на сегменты; каждый следующий сегмент вдвое больше предыдущего; новые сегменты выделяются по мере необходимости. Поскольку элементы не двигаются, указатели на них стабильны, не остаются “дыры” в арене, а доступ по индексу — за O(1).
Реализация
Структура на C:
typedef struct { u32 count; int used_segments; u8 *segments[26]; } SegmentArrayInternal;
Почему всего 26 сегментов? Из 64 бит указателя обычно реально используются 48, так что 49 сегментов уже перекрывают адресное пространство (~256 ТиБ). Я предпочитаю индекс u32 (до ~4 млрд элементов) — это даёт 32 сегмента. Ещё убираем 6 маленьких (1..32), начинаем с 64, остаётся 26 сегментов — хватает для 4 294 967 232 элементов (чуть меньше UINT32_MAX). Фиксированный массив рядом со структурой снижает риск промаха кэша.
Размеры сегментов — степени двойки: проще математика и быстрые сдвиги для индексов.
#define SMALL_SEGMENTS_TO_SKIP 6
#define log2i(X) ((u32) (8*sizeof(unsigned long long)
- __builtin_clzll((X)) - 1))
u32 capacity_for_segment_count(int segment_count) { return ((1 << SMALL_SEGMENTS_TO_SKIP) << segment_count) - (1 << SMALL_SEGMENTS_TO_SKIP); }
void *_sa_get(SegmentArrayInternal sa, u32 index, size_t item_size) { int segment = log2i((index >> SMALL_SEGMENTS_TO_SKIP) + 1); u32 slot = index - capacity_for_segment_count(segment); return sa->segments[segment] + item_sizeslot; }
log2i использует __builtin_clzll (подсчёт ведущих нулей) для быстрого вычисления номера сегмента.
Clang оптимизирует _sa_get до ~10 инструкций x86-64 (-O3), так что узким местом будет память, а не вычисления индекса. При последовательной итерации можно обходить сегменты напрямую; в segment_array.h есть макрос.
Выделение нового элемента:
u32 slots_in_segment(int segment_index) { return (1 << SMALL_SEGMENTS_TO_SKIP) << segment_index; }
void *_sa_alloc(SegmentArrayInternal *sa, size_t item_size) { if (sa->count >= capacity_for_segment_count(sa->used_segments)) { size_t segment_size = item_size * slots_in_segment(sa->used_segments); sa->segments[sa->used_segments++] = malloc(segment_size); } sa->count++; return _sa_get(sa, sa->count-1, item_size); }
Замечание: можно сделать ёмкость строго степенью двойки, если первые два сегмента одинакового размера. Код станет менее изящным, но это спасает от ~50% потерь памяти при использовании как массива бакетов в хеш-таблице со степенью двойки.
Дженерики
Я применяю технику из прошлой статьи для типобезопасного хранения любого типа. Макрос связывает тип с общей структурой:
#define SegmentArray(type)
union {
SegmentArrayInternal internal;
type *payload;
}
Дальше макросы используют payload, чтобы передавать сведения о типе…
Комментарии (77)
- Обсуждается структура «сегментированный массив» (экспоненциальные сегменты), её плюсы и минусы, и сравнение с существующими решениями: std::deque, ropes, Zig std.SegmentedList, rust-array-stump, plf::colony.
- Критика терминологии: это не «массив» в классическом смысле из‑за неконтигуозной памяти; многие API ожидают сплошной/страйдовый буфер и не подойдут.
- Производительность: при локальных L1-итерациях вычислительная часть индексации может быть ощутима; для больших объёмов память становится бутылочным горлышком. Предлагаются оптимизации итерации по сегментам и замечания про clz/bsr/lzcnt и опции компилятора.
- Виртуальная память как альтернатива: резервирование большого диапазона и по мере роста коммит страниц/guard pages; отмечены плюсы на Linux (MAP_POPULATE, mremap), но плохо для embedded/WASM.
- Сравнение с deque: фиксированные блоки vs экспоненциальные, поддержка prepend, рандом-доступ есть; реализация MSVC критикуется за малый размер блока, GNU/libc++ лучше.
- Недостатки сегментов: ухудшение предвыборки/кэш-локальности при линейной итерации, отсутствие стабильной непрерывности для API, сложность с хеш-таблицами при росте (rehash), потенциальный перерасход памяти при экспоненциальных размерах.
- Предложения: настраиваемый минимальный размер сегмента, функции «склейки» мелких сегментов, разбор условий, когда экспоненциальные сегменты оправданы, и замечания о чрезмерной макротрюковости в C/C23.
Zig Error Patterns
Введение
Я часто использую отладчик, но привык и к выводной отладке, особенно в юнит-тестах. Хотелось улучшить её и чаще подключать отладчик.
Улучшение выводной отладки
Главная проблема — «шум»: в цикле интересна одна итерация, а печатается всё. Или удобнее читать форматированную структуру, но приходится раскидывать print’ы по коду. В Zig тесты используют error’ы, значит можно печатать только при падении теста через errdefer:
test { errdefer std.debug.print("{f}", .{ast}); // ... }
Так контекст появляется только при ошибке, без засорения лога.
Запуск тестов в отладчике
Просто запустить seergdb или gdb -tui неудобно: тестовые бинарники лежат в zig-cache. Трюк из ziggит: build.zig может запускать команды и передавать путь артефакта:
// seergdb — GUI фронтенд для gdb const debugger = b.addSystemCommand(&.{ "seergdb", "--run", "--" }); debugger.addArtifactArg(exe_unit_tests);
const debug_step = b.step("debug", "Run unit tests under debugger"); debug_step.dependOn(&debugger.step);
Это запускает правильный бинарник. Но отладчик сработает лишь на брейкпоинте или панике, тогда как раннер тестов «проглатывает» ошибки.
Комбинация трюков
Добавим @breakpoint через errdefer:
test { errdefer @breakpoint(); }
Так мы попадаем в точку ошибки, видим контекст и вывод std.testing.expect*. Минус: при zig build test отчёт показывает падение всего шага тестов, а не отдельных кейсов. Нужна возможность включать брейкпоинты выборочно.
Условная компиляция
Через build options пробрасываем флаг, решающий, вызывать ли @breakpoint в тестах.
Минимальный скрипт сборки, запускающий тесты, дополняем опциями:
const std = @import("std");
pub fn build(b: *std.Build) void { const target = b.standardTargetOptions(.{}); const optimize = b.standardOptimizeOption(.{});
const lib = b.addModule("zig-test-patterns", .{
.root_source_file = b.path("src/root.zig"),
.target = target,
.optimize = optimize,
});
const options = b.addOptions();
options.addOption(bool, "debugger", false);
lib.addImport("config", options.createModule());
const mod_tests = b.addTest(.{ .root_module = lib });
const run_mod_tests = b.addRunArtifact(mod_tests);
const test_step = b.step("test", "Run tests");
test_step.dependOn(&run_mod_tests.step);
}
В коде тестов:
const std = @import("std"); const config = @import("config");
test "errdefer @breakpoint()" { errdefer if (config.debugger) @breakpoint(); return error.FixMe; }
test "no breakpoint" { return error.FixMe; }
zig build test — без брейкпоинтов. Но менять значение флага так — значит пересобирать build.zig. Добавим опцию прямо в систему сборки:
var options = b.addOptions(); const use_debugger = b.option( bool, "debugger", "Enables code intended to only run under a debugger", ) orelse false; options.addOption(bool, "debugger", use_debugger);
Теперь можно переключать поведением командой:
zig build -Ddebugger test
И, при желании, привязать шаг запуска отладчика к этому флагу.
Комментарии (46)
- Участники хвалят согласованность базовых конструкций Zig: минимализм синтаксиса и мощь comptime позволяют элегантные решения без излишней сложности.
- Особый интерес вызвал errdefer: многие отмечают, что это упрощает тесты и отладку; звучит мнение, что такую возможность «стоит иметь каждому языку».
- Обсуждают практики отладки: полезны советы по интеграции дебаггера в build.zig, что избавляет от ручного поиска исполняемого файла в кэше.
- Поднимается вопрос об ошибках без полезной нагрузки в Zig: при парсинге (например, JSON) типовые ошибки вроде UnexpectedToken недостаточно информативны; интересуются паттернами передачи дополнительного контекста.
- Есть замечание о смешении стилей именования (camelCase в stdlib vs snake_case у автора), что может сбивать с толку.
- Отмечают эстетику сайта и блога: шрифты (Berkeley Mono), цветовую схему и ретро-оформление — «как в старых DOS-играх».
- Проводится параллель с D: аналогичная идея реализована через scope(failure), что подчеркивает общность концепции.
Comptime.ts: compile-time expressions for TypeScript
Простой компилятор TypeScript для вычисления выражений с пометкой comptime на этапе сборки. Полезно для переноса вычислений из рантайма в компиляцию. Вдохновлено Bun macros и Zig comptime.
Внимание: вы сами отвечаете за безопасность выражений, вычисляемых на этапе компиляции. Изоляции нет. Импорты comptime допускаются только в файлах проекта (не в node_modules), но можно импортировать из node_modules как comptime.
Содержание
- Что такое comptime.ts?
- Примеры: 1) простая сумма; 2) CSS без рантайма; 3) константы во время сборки
- Установка
- Использование: Vite, Bun, CLI, API
- Принудительная оценка и промисы, отказ от «вирусности»
- Запуск кода после comptime, как работает, ограничения, практики, отладка, поддержка, лицензия
Что это comptime.ts вычисляет выражения при компиляции, сокращая работу в рантайме.
Примеры
-
Простая сумма import { sum } from "./sum.ts" with { type: "comptime" }; console.log(sum(1, 2)); // => console.log(3);
-
Emotion CSS без рантайма import { css } from "@emotion/css" with { type: "comptime" }; const style = css
color: red; font-size: 16px;; div({ class: style }); // => const style = "css-x2wxma"; div({ class: style });
Примечание: импорт @emotion/css удаляется. Стили нужно вывести отдельно (после comptime или плагином бандлера).
- Константы на этапе сборки import { ms } from "ms" with { type: "comptime" }; const HOUR = ms("1 hour"); // => const HOUR = 3600000;
Поддерживаются многие выражения (включая индексацию и импортированные константы), результат должен быть сериализуем в JSON. Импорты с type: "comptime" удаляются; лишнее убирает ваш бандлер.
Установка bun add comptime.ts pnpm add comptime.ts npm install comptime.ts
Использование
- Vite: import { comptime } from "comptime.ts/vite"; export default defineConfig({ plugins: [comptime()] });
Только в прод-сборке, если поведение совпадает с рантаймом: export default defineConfig({ build: { rollupOptions: { plugins: [comptime()] } } });
- Bun: import { comptime } from "comptime.ts/bun"; await Bun.build({ entrypoints: ["./index.ts"], ou ... })
Комментарии (30)
- Обсуждение крутится вокруг идеи “comptime”/макросов в JS: часть хочет Rust‑подобные макросы и proc‑макросы (вплоть до JSX как jsx! или вообще писать фронт на Rust/wasm), другая сторона категорически против макросов в TS/JS.
- Есть путаница в терминах: “макросы” vs “comptime”; участники критикуют переиспользование терминов и вспоминают неудачный опыт sweet.js.
- Практические вопросы: можно ли делать агрессивный dead‑code elimination через if (comptime …) как в C препроцессоре? Ответ: само comptime подставит true/false, но для выкидывания веток нужен отдельный шаг минификатора/бандлера (Vite/Bun поддержат).
- Дискуссия об импорте with { type: 'comptime' }: одни считают это неправильным использованием атрибута type (ожидается соответствие MIME), другие указывают, что спецификация оставляет семантику type открытой.
- Обсуждают границы возможности: поддержка типов/генериков на уровне comptime (как в Zig) пока ограничена; возврат именованных функций и сложные случаи с замыканиями не поддерживаются из‑за требований к гарантиям и сохранению функций между процессами.
- Альтернативы: настроить сборку для JSX без макросов; использовать библиотеки вроде lite-jsx; для Rust‑фронта рекомендуют Dioxus/Leptos; спорят о реальной применимости wasm и памяти/управления ей в вебе.
- Применимость: идея удобна для предсборки (например, markdown) и константной подстановки, но не заменяет полноценных препроцессоров/макросистем уровня Rust/Zig.