TIL blog

技術ネタ, その他学んだことのアウトプット用

プログラミング言語 Zigについて簡単に調べた

最近, Quoraで尊敬するエンジニアの方々の回答を眺めるのが趣味なのだが, 回答で少し気になったものがあった。

これから間違いなく需要があるプログラミング言語はどれになりますか? - Quora

こちらのMatzの回答で, 「未来に需要が高まると良いな」と思っている言語として Julia, Crystal, V, Zig があげられている。 Juliaは研究で使っていた, Crystalは趣味で少し書いた, VはTwitterで見かけたので知っていたがZigは聞いたことないなと思ったので少し調べてみた。

ググったり, qiita検索しても日本語の記事は見当たらなかったので, まだマイナーな模様。 はてぶで何人か言及しているくらい。 http://b.hatena.ne.jp/entry/ziglang.org/

対抗言語は 同じく Cのreplace狙っている C++, Rust, Dあたりぽい。

公式ドキュメントのFeature Highlight から特に気になったものを抜粋する. https://ziglang.org (調べただけで実際に動かしてはないので勘違いがあるかも)

Small, simple language

プログラミング知識のデバッグではなく, アプリケーションのデバッグに集中するための言語 とある。 実際文法の仕様も500行に収まっている模様。 https://ziglang.org/documentation/master/#Grammar

また, C++, D, Rust の以下のような 隠された制御フローを持たない

  • operator overloading
  • throw, catch による異なるmethod呼び出し

Performance and Safety: Choose Two

パフォーマンスと安全性を両立している

パフォーマンスに関して, Cより高速 (すごい)
理由は以下らしいが低レイヤの知識が怪しくて詳細は理解できていない...

また, 安全性の観点からは overflowなどはbulid optionを付けることでコンパイル時に詳細に検出することが可能になっている。

test "integer overflow at runtime" {
    var x: u8 = 255;
    x += 1;
}
$ zig test test.zig
1/1 test "integer overflow at runtime"...integer overflow
/home/andy/dev/www.ziglang.org/docgen_tmp/test.zig:3:7: 0x2040f0 in test "integer overflow at runtime" (test)
    x += 1;
      ^
/home/andy/dev/zig/build/lib/zig/std/special/test_runner.zig:13:25: 0x22752a in std.special.main (test)
        if (test_fn.func()) |_| {
                        ^
/home/andy/dev/zig/build/lib/zig/std/special/bootstrap.zig:126:22: 0x226cb5 in std.special.posixCallMainAndExit (test)
            root.main() catch |err| {
                     ^
/home/andy/dev/zig/build/lib/zig/std/special/bootstrap.zig:47:5: 0x226a20 in std.special._start (test)
    @noInlineCall(posixCallMainAndExit);
    ^

Tests failed. Use the following command to reproduce the failure:
/home/andy/dev/www.ziglang.org/docgen_tmp/test

パフォーマンスのボトルネックになりそうなら未定義動作を許容することも可能

test "actually undefined behavior" {
    @setRuntimeSafety(false);
    var x: u8 = 255;
    x += 1; // XXX undefined behavior!
}

A fresh take on error handling

try catch による例外処理を持っている, errorが起きないというケースのassert をunreachableで行うというのは他の言語ではあまり見ない仕様かもしれない。

unreachable.zig

const std = @import("std");
const File = std.os.File;

pub fn main() void {
    const file = File.openRead("does_not_exist/foo.txt") catch unreachable;
    file.write("all your codebase are belong to us\n") catch unreachable;
}
$ zig build-exe unreachable.zig
$ ./unreachable
attempt to unwrap error: FileNotFound
/home/andy/dev/zig/build/lib/zig/std/os.zig:530:33: 0x206411 in std.os.posixOpenC (unreachable)
                posix.ENOENT => return PosixOpenError.FileNotFound,
                                ^
/home/andy/dev/zig/build/lib/zig/std/os/file.zig:37:24: 0x2061c7 in std.os.file.File.openReadC (unreachable)
            const fd = try os.posixOpenC(path, flags, 0);
                       ^
/home/andy/dev/zig/build/lib/zig/std/os/file.zig:50:13: 0x21c8e3 in std.os.file.File.openRead (unreachable)
            return openReadC(&path_c);
            ^
???:?:?: 0x2272a7 in ??? (???)


/home/andy/dev/www.ziglang.org/docgen_tmp/unreachable.zig:5:58: 0x2271d5 in main (unreachable)
    const file = File.openRead("does_not_exist/foo.txt") catch unreachable;
                                                         ^
/home/andy/dev/zig/build/lib/zig/std/special/bootstrap.zig:116:22: 0x226bda in std.special.posixCallMainAndExit (unreachable)
            root.main();
                     ^
/home/andy/dev/zig/build/lib/zig/std/special/bootstrap.zig:47:5: 0x2269d0 in std.special._start (unreachable)
    @noInlineCall(posixCallMainAndExit);
    ^

Generic data structures and functions

多言語にもよくある型変数とジェネリクスによるシンプルなデータ構造の定義が可能

test.zig

const std = @import("std");
const assert = std.debug.assert;

test "types are values" {
    const T1 = u8;
    const T2 = bool;
    assert(T1 != T2);

    const x: T2 = true;
    assert(x);
}
$ zig test test.zig
1/1 test "types are values"...OK
All tests passed.

generics.zig

const std = @import("std");

fn List(comptime T: type) type {
    return struct {
        items: []T,
        len: usize,
    };
}

pub fn main() void {
    var buffer: [10]i32 = undefined;
    var list = List(i32){
        .items = &buffer,
        .len = 0,
    };

    std.debug.warn("{}\n", list.items.len);
}
$ zig build-exe generics.zig
$ ./generics
10

おわりに

プログラミング言語 Zigについて, 公式ドキュメントを参照して主な機能について簡単に紹介した。
今回紹介した機能以外にも https://ziglang.org/#Feature-Highlights に主要な機能がまとまっているので, 気になった人はぜひ読んでみて(あわよくば解説記事を書いて)ほしい。
rust にやりたいと思いつつ, 所有権で挫折していたので, Zigもドキュメント読みながら軽く触ってみる予定。