HN 日本語サマリー

← 一覧へ戻る
プログラミング

Zigを4ヶ月使ってみて

Four Months of Zig (gracefulliberty.com)

25 pointsby ibobev11 コメント

要約

著者が数年ぶりにZig言語に戻り、4ヶ月間の開発経験を共有する記事です。プロジェクトでの利用、Zig Dayへの参加、anyzig、IOとアロケータ、comptime、ビルドシステム、依存関係文化、エラーハンドリング、増分コンパイルといったZigの長所について、Rustとの比較を交えながら詳細に解説しています。一方で、標準ライブラリの安定性、ライフタイムサポート、ドキュメント不足、comptimeでのアロケータ、ブートストラップの改善点についても触れています。

全文翻訳

Zigを4ヶ月使ってみて

2026-10-27 · 15 分 · #computing

数年ぶりにZigに戻ってきてから約4ヶ月が経ちました。この間、Zigでいくつかのソフトウェアを書き、オンラインや対面でコミュニティと再交流しました。これまでのZigで気に入っている点と、そうでない点を含め、その経験の一部を共有することにしました。以前よく使っていた言語であるRustとの比較も随時含めます。

プロジェクト

Zigで最初に始めたプロジェクトはsnurlでした。これはsmallnet(Gemini、Finger、Gopher、Spartanなど)と対話するためのライブラリです。私の目標は、curlのsmallnet版の代替を提供し、同様のテストとファジング要件を持ちながらも小規模にすることでした。可能な限りTigerStyleの考え方に従おうとしました。

早期に直面した問題の一つは、ファージャーが実際には機能しなかったことです。前回の投稿でファジングに興奮していましたが、その機能がまだ完成していないことに気づきませんでした。Zigの現状を考えると驚くことではありませんが、zig initによって提供されるmain.zigファイルでファージャーがデモンストレーションされているだけに、がっかりしました。

その後、まだ公開していない2つのプログラムを書きました。1つ目は小さなTUIタイピングレーサーです。最小限のバージョンを動作させるのは予想以上に簡単でした。2つ目はraylibを使った恒星進化を伴うn体シミュレータです。

Zig Day

ここ数ヶ月で最もエキサイティングな機会は、地元のZig Dayに参加できたことでした。8月20日にLobstersでZig Day Seattleが開催されることを知りました。近隣でZig Dayが開催されることを知り、興奮しました。そしてAndrew Kelleyが参加すると知り、さらに興奮しました。

Zig Daysは、Zigに興味のある人々が集まり、一緒にプロジェクトに取り組み、Zigについて話し合うローカルミートアップです。このZig Dayでは、snurlに取り組むことにしました。友人であるEvin Yuloも参加することにしました。

イベント自体はBothell図書館で開催されました。参加者が多すぎて収容能力を超えたため、Bellevue図書館から移動したのです。Zigのクリエイターがイベントに参加すると、そうなります。

私はこれらのZig Daysの形式を気に入っており、コミュニティの一部であることを嬉しく思っています。ローカルグループによって運営されているため、Zigコミュニティ全体がより一体感を感じられます。これは、Zigに興味のある他の人々と直接交流する方法です。そして、この場合はZig自体のクリエイターともです。

他のプログラマーと彼らのプロジェクトについて話す機会を得ました。うまくいけば、私たちのプロジェクトすべてをより強くするような思想的な相互受粉があったことでしょう。最終的に、snurlをevinと一緒に作業しました。彼はZigの標準ライブラリTLS実装を代替バックエンドとして統合する作業を開始しました。

Andrew Kelleyとも短時間話しました。Zigの組み込みファジングがすぐに修正されることを願っています!

Ryan Hendricksonは、彼の視点からその日のイベントのさらに詳しい概要を素晴らしい記事にまとめていますので、詳細を知りたい方はそちらをご覧ください。

将来もZig Day Seattleに間違いなく参加するでしょう。次のローカルイベントまでにポートランドで開催されるものにも参加するかもしれません。Zigとその価値観に興味を持つ他の人々とつながる機会を楽しんでいます。

気に入っている点

anyzig

anyzigが大好きです。異なるプロジェクトでzig masterと0.16.0を使用する必要がありましたが、anyzigのおかげでそれが可能になりました。

残念ながら、build.zig.zonがないディレクトリの外では機能しません。つまり、zigコマンドを必要とするツールは、プロジェクトディレクトリ内でのみ動作します。これは、単発のZigスクリプトの自動フォーマットを壊します。その場合、デフォルトのzigバージョンを提供できるかもしれません。

IOとアロケータ

一部の人々をイライラさせることは承知していますが、ZigではIOとアロケータのパラメータを関数に渡す必要があるという事実が気に入っています。

アロケータ

アロケータから始めましょう。これらはより長く存在しています。各Zig関数では、明示的なアロケータパラメータを受け入れる必要があります。これは、グローバルに変更可能なデフォルトアロケータを使用するか、ローカルのcontextで変更するかのどちらかであるほとんどのプログラミング言語とは異なります(Odinを参照)。

コードの異なる部分でアロケータを変更できるのが気に入っています。一部の処理にはアリーナアロケータを使用したいかもしれませんが、他の処理には汎用アロケータが必要になる場合があります。時にはFixedBufferAllocatorだけで操作を実行できることもあります。Zigのスタイルにより、これらすべてを簡単に処理できます。

Zigのシステムは、Odinの暗黙的なcontextシステムよりも好ましいです。なぜなら、Zigは物事を明示的に保つからです。関数がメモリを割り当てるかどうかは明らかであり、間違ったアロケータを渡すことは困難です。

これは、Rustの隠された、失敗しない割り当て(メモリが枯渇するとパニックする)よりも優れています。明示的な割り当てを追加する作業が行われていますが、これは言語に後付けされる機能であり、最初から構築されたものではありません。

Zigではメモリを割り当てるプログラムを推論するのがはるかに簡単です。

IO

IOパラメータはさらに強力で、たとえそれが新しいものであってもです。それをもたらすために必要な破壊的な変更(0.15.0から0.16.0への移行をスキップしたとしても)の価値は十分にあります。Zigでは、基盤となるオペレーティングシステムと対話するすべての関数(ただし例外あり)には「IO」パラメータが必要です。これは、入力、出力、およびその他のすべてのコンテキストを提供します。Zigを新しいオペレーティングシステムに移植することは、主にIOの移植です。

実際には、これはテストに非常に役立ちます。動作をテストする場合、必要なとおりに機能するテストIOインスタンスを渡すだけで済みます。入力ストリームを自由に操作したり、書き込みを失敗させたり、その他何でもできます。

割り当てと同様に、IO引数を渡すことで、どのプログラムが純粋で、どのプログラムがそうでないかが明確になります。プログラムが外部の何かを変更するかどうかを一目で判断できます。

Zigは、シンプルさを保ちながら強力な機能を追加するという点で、非常に優れた実績を持っています。わずかに異なる類似したことを行う100個の小さな機能を追加する代わりに、さまざまなユースケースすべてをサポートする1つの主要な機能を提供することがよくあります。ローエンド、ハイシーリング。

Comptime

comptimeが大好きです。これは、メタプログラミングと事前計算をすべて1つにシームレスに行う方法です。他の人々がより詳細な説明を書いていますが、私は先に進みます。

ビルドシステム

Zigのビルドシステムは素晴らしいです。Uberのような企業が他の言語で書かれたソフトウェアに採用するほどです。

私が気に入っている点の一つは、Cargoが文句を言うような方法で他のツールとシームレスに統合できることです。これは、コード生成を含む私のプロジェクトにとって特に重要です。

依存関係文化

Zigには優れた依存関係文化があります。主な精神はシンプルです:避ける。依存関係が必要ない場合は、追加しないでください。しかし、必要な場合は、多くの場合、Zigがtranslate-cで簡単に統合できる、実績のあるライブラリです。外部依存関係を簡単にベンダーインしてコードを監査することもできます。

私のZigプログラムのほとんどは、直接のZig依存関係が1つか2つで、間接的な依存関係はゼロです。これにより、コードベースの監査と制御がはるかに容易になります。

これはRustとは対照的です。Rustでは、私の最小限のプロジェクトでも、通常、いくつかの直接依存関係と数十の間接依存関係があります。

これは、Zigの依存関係文化と、リフレクション、乱数生成、クリーンなエラーハンドリング、JSON解析などの基本的な機能が、個別のライブラリとして維持されるのではなく、言語または標準ライブラリに組み込まれていることの両方のおかげです。すべてのプログラムでserdeやsynに依存する必要はありません。

Zigは、依存関係を追加する前に慎重に検討することを奨励しており、私はそれを高く評価しています。

エラーを楽に処理する

Zigは、デフォルトでエラーを正しく処理するようにプログラマーを促します。Zigでエラーを処理する最も簡単な方法は、tryキーワードを使用し、関数の戻り値の型に!を追加することです。

これは、プログラマーをコードにパニックを挿入するように導くRustとは対照的です。問題は、プロトタイピング中にパニックさせる方が簡単で、その後、コードに長く残してしまうことが多いことです。私は、エラーを返す代わりにパニックするRustで書かれた本番コードを見たことがあります。

Rustでは?を使用できます。これはunwrapよりも高速ですが、Result<Type, Box<dyn std::error::Error>>のようなものも行う必要があります。それは長すぎます!あるいは、anyhowクレートを使用してanyhow::Resultを返すこともできます。これは便利なヘルパーメソッドも提供します。しかし、合理的なエラーハンドリングのために依存関係を追加する必要があります。また、Zigスタイルのコンポーザブルエラーもあり、さらに別のライブラリが必要です。

増分コンパイル

Zigのコアチームメンバーは、増分コンパイルにおいて驚くべき仕事をしてきました。zig build --watch -fincrementalを実行すると、コンパイラは変更を監視し、変更されたものを正確にチェックし、リンクまで変更されたものだけを修正します。必要な以上の労力はかからないため、大規模なコードベースでも人間の知覚よりも高速です。Zigは、この動作をサポートするためにゼロから設計されました。

これにより、非常に優れたワークフローが実現します。コンパイラを増分モードでテキストエディタのすぐ隣で実行し、保存するたびにコードの更新を取得できます。他のことに気を取られる時間はありません。Rustプロジェクトでは、小さなプロジェクトでも10秒以上の増分コンパイルループが一般的でした。これは気を取られるには十分な時間ですが、他のことを生産的に行うには不十分な時間であり、Zigが排除する煩わしいギャップを残します。

Rustはここで不利です。これは後方互換性を維持する必要がある安定した言語です。これは、少なくとも大幅な改善のために、コンパイル速度を向上させるために物事を壊す余裕がないことを意味します。一方、Zigをより良くするために、メンテナーは最終結果が完璧であることを保証するためにほぼ何でも壊すことをいとわないでしょう。

現在、Zigはx86_64のLinuxとmacOSでのみ増分コンパイルをサポートしています。別のオペレーティングシステムやアーキテクチャを使用している場合は、まだこの機能にアクセスできませんが、その場合は注意すべきもう1つの点です!

これにより、Zigはさらに少し使いやすくなります。私はそれを歓迎します。

見たいこと

安定性の向上

他のすべてのZigユーザーと同様に、標準ライブラリがより安定することを望んでいます。それが1.0前の最後のタスクの1つであり、それ以前に多くのタスクがあることは知っていますが、エコシステムでの絶え間ない破壊に対処するのはイライラします。私の理解では、0.17.0のリリースに時間がかかったのはそのためです。

Andrew KelleyはZig Dayで、誰よりも1.0を見たいと言っていました。私は彼を信じているので、忍耐強く、最終バージョンが優れていると信頼します。

これは、私がまだ一部のプロジェクトでRustを使用している唯一の理由です。一部のケースでは、安定したプログラミング言語とそのエコシステムが必要です。しかし、今日Zigで構築されている印象的なソフトウェアを考慮すると、安定性だけがすべてではありません。そして、Zigの利便性がその不安定さを上回るプロジェクトもあります。1.0が待ちきれません。

ライフタイムサポート

Zigコンパイラでのライフタイムサポートの向上を望んでいます。具体的には、デバッグモードでローカル変数を返すことを、組み込みリンターのようなもの(Andrew Kelleyが実装したいと述べている)として、または関数が返された後にそのメモリを無効にすることとして、可能にしたいです。そうすれば、新しいユーザーはすぐにそのパターンを避けることを学びます。現在、理解していると思っていても、意図せずにコードを壊してしまうのは簡単です。

これに関連して、コンパイラは現在、将来壊れるコードを受け入れています。コンパイラは変数をブロックのスコープではなく、全体のスコープで生かします。これは、バッファをスタック割り当てしてブロックから返す場合、そのバッファは無効になるはずですが、そうではないことを意味します。私の理解では、これは将来のZigバージョンで静かに壊れる可能性があります。

// これは機能しますが、無効になります。
const foo = blk: {
	var buf: [1024]u8 = undefined;
	const n = try writeToBuf(&buf);
	break :blk buf[0..n];
};
ドキュメントの拡充

Zigはドキュメントが不十分です。始めるには十分ですが、さらに進むには、時々関数に添付されている、まばらなドキュメントコメントから意図を解釈する必要があります。例はまれです。私や友人でさえ、バッファを正しく設定する方法を見つけられなかったため、snurlでZigの標準ライブラリTLSを機能させる方法がまだわかりません。

このドキュメント不足のため、堅牢なZigプログラムを構築するための知識の多くはウェブ上に分散しています。Zigコミュニティに十分に統合されており、既存のドキュメントを読み、プレゼンテーションを視聴し、コードを読んだことがあるなら、成功できます。しかし、それほど統合されていない場合は、効果的に作業するのが難しい場合があります。

この利点は、人々がZigコミュニティに参加することを奨励することです(たとえば、私はMatrixルームの管理者です)。LLMが人間の協力を破壊しようとする一方で、私たちはかつてないほど人間の協力が必要です。しかし、私たちはそれと優れたドキュメントを両立させることもできます。ご存知のとおり、ドキュメントが充実していても、人々は質問をします。そして、優れたコミュニティは、単に「RTFM」と言うだけでなく、人々を適切なリソースに導く方法を知っています。

また、Zigとリテラルプログラミングの交差点がどのようなものになるかにも興味があります。私のリテラルプログラミングツールは現在Rustで書かれていますが、それは変わるかもしれません。

Comptimeアロケータ

コンパイル時にJSONを解析したいです。私のプロジェクトの1つでは、バイナリ内に保存されているJSONファイルがあります。これは静的であり、コンパイル時に構造体のコレクションに解析できます。

しかし、標準ライブラリのJSONパーサーはアロケータを必要とします。コンパイル時に動作するアロケータがないため、JSON解析はすべて実行時に行う必要があります。それが私のプロジェクトで行ったことです。

アロケータを必要としないJSONパーサーを追加する意図があると思います(結局のところ、データはすでにJSON文字列に存在します)。それは当面の問題を解決しますが、アロケータを必要とするより一般的なケースがあります。以前はFixedBufferAllocatorがコンパイル時に機能し、この目的を果たしていたと思います。再びそうすることができます。

より良いブートストラップ

Zigのブートストラップストーリーは印象的です。C++版のコンパイラを削除し、小さなWASMブロブとWASMインタプリタに置き換えました。WASMファイルはコンパイラの縮小版で、完全なZigコンパイラをCにコンパイルし、それをシステムCコンパイラでコンパイルします。興味深いアプローチであり、詳細を知りたい場合はリンクされた記事を読むべきです。

この唯一の注意点は、ソースコードにチェックインされたコンパイル済みバイナリブロブが必要であることです。これは完全な以前のコンパイラ(Rustなど)を必要とするよりは良いですが、すべてのステップでプロセス全体で完全なソースが利用可能であることほど良くはありません。悪意のあるアクターはブロブに何かをこっそり忍び込ませる可能性があります。さらに重要なことに、Debianのような多くのディストリビューションは、ガイドラインに準拠する方法でZigをパッケージ化することが不可能であるため、現時点ではZigを適切にパッケージ化できません。

彼らの元の計画は、コンパイラのCバックエンドを使用してCバージョンのコンパイラを生成し、それを別途維持することでした。その後、2つの異なるソースバージョンを持つことになります。彼らはこのアプローチが難しすぎると判断しました、残念ながら。

このため、ブートストラッププロセスを改善するために、別の言語(おそらくC)で別のZigコンパイラを作成する必要があります。これは、Zig Software Foundationが現在開発したいと考えているものではありません。これは、現時点ではソースからZigを完全にブートストラップする方法がないことを意味します。

この問題は理論的な問題だけではありません。ZigはDebianでパッケージ化できないため、プロジェクトの1つで別の言語を選択して、より広い使用可能性を確保する必要がありました。

幸いなことに、この問題は一時的です。Zigが安定すれば、代替コンパイラの構築は簡単になるはずです。Zigは、他の言語とは異なり、代替実装が人間的に達成可能であるシンプルな言語として設計されています(他の言語など)。現在の不安定さは、代替コンパイラが絶え間ない追いつきゲームをすることになることを意味し、おそらくコアチームが急速にイテレーションしている間にそれを管理したくない理由です。

alas、これも1.0を待つ必要があるかもしれません。早く来てほしいです!

今後

Zigを使い続けます。その方向性に興奮しており、コミュニティの一員であり続けることを楽しみにしています。これまでのところ、欠点があったとしても、Zigよりも好む他のプログラミング言語は見つかっていません。リリース間で大規模な変更を行う必要がないほど安定しています。ほとんどのプロジェクトで、私の主要なプログラミング言語であり続けるでしょう。

これらのプロジェクトの1つがReTangledです。以前はRustで書かれていましたが、巨大な依存関係ツリーにうんざりし、Zigのビルドシステムを最大限に活用したいと思いました。

また、Zigに直接貢献することをさらに検討しています。学生としての限られた時間、Zigの貢献者の過剰な数、そして不十分なドキュメントを考えると、これは挑戦となるでしょう。しかし、貢献し、プロジェクトに影響を与え、より優れたソフトウェアエンジニアになりたいと思っています。幸いなことに、貢献者のオンボーディングの改善は、Andrew Kelleyが今後優先することのようです。

また、将来のZig Days(シアトル)にも参加します。もし会って一緒にZigプロジェクトに取り組みたいなら、ぜひ来てください!