← Back to context

Comment by weinzierl

18 hours ago

Two additional points:

1. Tooling (as an extension to the mentioned IDE support point). Zig and Rust are both praised for their tooling and I think rightfully so. The C/C++ interop story and the cross-compiling story in Zig are great. From the standpoint of a working practitioner though I think Rust is way ahead. Not surprising given that Zig is much younger, but something to keep in mind.

2. Compile Time Stuff: Here Zig is praised and Rust not so much. I think this is undeserved. Rust has much higher aspirations for their compile time features, namely that outcome must be identical regardless when the code runs. This is a very useful property but makes the task much harder and fundamentally incomparable with Zig comptime.

Are you saying that you think that Zig does not produce identical outcomes for comptime code regardless of when the code runs? What do you mean?

  • Yes. For example in Rust it took a long time for floating point operations to be available at compile time and even now only a subset is. The reason is that a lot of energy and thought went into the issue of producing identical output (and what identical precisely means ) even when compilation is on a different processor than where the target runs.

    As far as I know this is not a concern for Zig comptime.

    • Zig Comptime uses softfloat so it has architecture independent determinism.

      And the zig core team is absolutely concerned with bitwise determinism in the compiled artifacts, iirc this is why they rejected the sloppy bun PR to the compiler.

      1 reply →

    • there has been a ton of work on making comptime a pure and deterministic execution environment. I do not expect that work to stop. I don't know where you are getting the idea that it is not an important design consideration for the language.

      to expand, if two different host platforms cross compiling to the same target platform have different results, I am almost certain that would be considered a compiler bug.

      if you're pointing out that a runtime operation and a compile time operation might not agree, I'd be more interested in understanding when that would ever have any meaningful impact on anything. given the compilation is supposed to be deterministic, the difference can easily be addressed by comptime branching on target architecture in the rare case that it matters for your program.

      10 replies →

    • What's your source for this? Comptime Zig code can do pointer casts and whatnot, all emulated as if run on the target bitness/endianness/etc. And any operations that are undefined on the target platform result in a compile error. I've never had an issue cross-compiling.

      5 replies →

    • In C++ as well, constexpr math introduced in C++23 has similar concerns regarding floating point accuracy.

  • I assumed that it meant that if you ran code at compile time or at runtime, the results should be exactly the same given the same inputs.

Zig comptime feels easier and more effective in practice. I've had some fun const evaluating some stuff in Rust, but I needed to use a bunch of annoying imperative hacks because so much of the functional stuff wasn't supported in const context back then. It's probably a bit better these days.

For one of my crates I needed to have a build script make a bunch of lookup tables as separate files for me to `include_bytes!` because at the time I couldn't generate a bunch of floating point conversions in const.

  • Certainly every new Rust release tends to have either new things which were stabilized as const on day one, or things which already existed but now have stable const.

    The biggest constraint today on Rust's constant evaluation compared to where you'd expect is that trait implementations can't ever be constant, this obviously means you can't call SomeTrait::function in your constant, even if you can see the implementation of SomeTrait::function and if it were not a trait it'd obviously be constant -- but it also means sugar like Rust's for loop, which de-sugars into trait invocations, can never be constant today.

    I think we can expect that to get fixed in the relatively near future, but I'd have said that last year too so what do I know.

    If you have C++ experience you'd probably want a lot more. C++ is allowed to allocate inside constant evaluation, and I believe in C++ 26 it's now even allowed to persist the allocation to runtime rather than being required to always clean up during compilation, so that's a much bigger set of crazy things you can do at compile time.

    • > it also means sugar like Rust's for loop, which de-sugars into trait invocations, can never be constant today.

      Yep, that was my annoyance.

      Const allocation is possible in Rust as an unstable feature. Not sure if you can persist it to runtime, though you can persist a reference which will become a static reference. I think it being unstable is why I needed `include_bytes!`.

      1 reply →