HN2new | past | comments | ask | show | jobs | submitlogin

This is exactly Zig's strength, not its problem. The flexibility/lack of interfaces allows you to choose the correct abstraction for the given task. In C++, every writer is `anytype`, in Java every writer is `AnyWriter`, in Rust every writer is `GenericWriter`. They all have tradeoffs but "fits better due to language design" shouldn't be one of the tradeoffs considered.


> in Rust every writer is `GenericWriter`.

I may be misunderstanding the article - but it looks like GenericWriter in zig still has dynamic dispatch overheads at runtime in all cases. Rust traits are more like “anytype” - since they get monomorphized by the compiler and have no runtime overhead at all. But unlike zig’s anytype, traits have excellent documentation (since they’re explicit, not implicit interfaces). Rust can also implicitly create an “AnyWriter” style object if you don’t want monomorphization via &dyn Trait. But you often don’t need to, because you can store trait objects in other structs just fine. - Though admittedly, you can do the same in zig via comptime structs.

There are a lot of things I admire about zig. But for interfaces like Writer, rust’s trait system seems like the better tool. I wish zig would copy rust’s trait system into the language.


No, GenericWriter takes a function at compile time and it gives you a GenericWriter struct that calls that function (at compile time), no function pointers needed.


There's definitely overhead with the GenericWriter, seeing as it uses the AnyWriter for every call except `write` (1)

    genericWriter        - 31987.66ns per iterations
    appendSlice          - 20112.35ns per iterations
    appendSliceOptimized - 12996.49ns per iterations

`appendSliceOptimized` is implemented using knowledge of the underlying writer, the way that say an interface implementation in Go would be able to. It's a big part of the reason that reading a file in Zig line-by-line can be so much slower than in other languages (2)

(1) https://gist.github.com/karlseguin/1d189f683797b0ee00cdb8186...

(2) https://github.com/ziglang/zig/issues/17985


Nice! It'd be fun to see a comparison in rust if anyone is keen. - Both code and resulting performance.


I was curious, so I ran your zig version myself and ported it to rust[1].

I think you forgot to run your benchmark in release mode. In debug mode, I get similar results to you. But in release mode, it runs ~5x faster than you reported:

    genericWriter        - 4035.47ns per iterations
    appendSlice          - 4026.41ns per iterations
    appendSliceOptimized - 2884.84ns per iterations
I bet the first two implementations are emitting identical code. But appendSliceOptimized is clearly much more efficient.

For some reason, rust is about twice as fast as zig in this test:

    generic_writer          time:   [1.8812 µs 1.8837 µs 1.8870 µs]
    append_slice            time:   [2.0019 µs 2.0065 µs 2.0126 µs]
    append_slice_raw        time:   [1.6932 µs 1.7041 µs 1.7182 µs]
(1µs = 1000ns)

[1] https://gist.github.com/josephg/e2dd6e7baf0a764a21bd724f8a2e...

Tests running on linux 6.8.0, CPU: Ryzen 7950x. zig v0.13 / rust v1.84.1.

Zig command: zig build --release=fast -Dtarget=native run

Rust command: RUSTFLAGS='-C target-cpu=native' cargo run --release -- --bench




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: