←back to thread

Things Zig comptime won't do

(matklad.github.io)
458 points JadedBlueEyes | 6 comments | | HN request time: 0.002s | source | bottom
Show context
forrestthewoods ◴[] No.43746616[source]
> When you execute code at compile time, on which machine does it execute? The natural answer is “on your machine”, but it is wrong!

I don’t understand this.

If I am cross-compiling a program is it not true that comptime code literally executes on my local host machine? Like, isn’t that literally the definition of “compile-time”?

If there is an endian architecture change I could see Zig choosing to emulate the target machine on the host machine.

This feels so wrong to me. HostPlatform and TargetPlatform can be different. That’s fine! Hiding the host platform seems wrong. Can aomeone explain why you want to hide this seemingly critical fact?

Don’t get me wrong, I’m 100% on board the cross-compile train. And Zig does it literally better than any other compiled language that I know. So what am I missing?

Or wait. I guess the key is that, unlike Jai, comptime Zig code does NOT run at compile time. It merely refers to things that are KNOWN at compile time? Wait that’s not right either. I’m confused.

replies(1): >>43746888 #
1. int_19h ◴[] No.43746888[source]
The point is that something like sizeof(pointer) should have the same value in comptime code that it has at runtime for a given app. Which, yes, means that the comptime interpreter emulates the target machine.

The reason is fairly simple: you want comptime code to be able to compute correct values for use at runtime. At the same time, there's zero benefit to not hiding the host platform in comptime, because, well, what use case is there for knowing e.g. the size of pointer in the arch on which the compiler is running?

replies(1): >>43747015 #
2. forrestthewoods ◴[] No.43747015[source]
> Which, yes, means that the comptime interpreter emulates the target machine.

Reasonable if that’s how it works. I had absolutely no idea that Zig comptime worked this way!

> there's zero benefit to not hiding the host platform in comptime

I don’t think this is clear. It is possibly good to hide host platform given Zig’s more limited comptime capabilities.

However in my $DayJob an extremely common and painful source of issues is trying to hide host platform when it can not in fact be hidden.

replies(1): >>43747513 #
3. int_19h ◴[] No.43747513[source]
Can you give an example of a use case where you wouldn't want comptime behavior to match runtime, but instead expose host/target differences?
replies(1): >>43747584 #
4. forrestthewoods ◴[] No.43747584{3}[source]
Let’s pretend I was writing some compile-time code that generates code. For example maybe I’m generating serde code. Or maybe I’m generating bindings for C, Python, etc.

My generation code is probably going to allocate some memory and have some pointers and do some stuff. Why on earth would I want this compile-time code to run on an emulated version of the target platform? If I’m on a 64-bit platform then pointers are 8-bytes why would I pretend they aren’t? Even if the target is 32-bit?

Does that make sense? If the compiletime code ONLY runs on the host platform then you plausibly need to expose both host and target.

I’m pretty sure I’m thinking about zig comptime all wrong. Something isn’t clicking.

replies(2): >>43750150 #>>43772425 #
5. von_lohengramm ◴[] No.43750150{4}[source]
It sounds like the sort of compile-time code that you're talking about is closer to "buildtime" code in Zig, that is Zig code compiled for the host platform and executed by the build system to generate code (or data) to be used when compiling for the target system. As it stands now, there's absolutely nothing special about buildtime code in Zig other than Zig's build system providing good integration.

On the other hand, "comptime" is actually executed within the compiler similar to C++'s `consteval`. There's no actual "emulation" going on. The "emulation" is just ensuring that any observable characteristic of the platform matches the target, but it's all smoke and mirrors. You can create pointers to memory locations, but these memory locations and pointers are not real. They're all implemented using the same internal mechanisms that power the rest of the compilation process. The compiler's logic to calculate the value of a global constant (`const a: i32 = 1 + 2;`) is the "comptime" that allows generic functions, ORMs, and all these other neat use cases.

6. CRConrad ◴[] No.43772425{4}[source]
> Why on earth would I want this compile-time code to run on an emulated version of the target platform? If I’m on a 64-bit platform then pointers are 8-bytes why would I pretend they aren’t? Even if the target is 32-bit? Does that make sense?

Nope, sorry, to me it doesn't. If you're cross-compiling for some other platform, then yes, I'd think you want the generated binary to be compatible with the target platform. And in order to verify that that binary code is correct for that target platform, you need to "allocate some memory and have some pointers and do some stuff" as you do on that platform.

So why on Earth would you want stuff -- like pointer sizes and whatnot -- to not be compatible with the target platform, but with whatever you happen to be compiling on? What good is pointer size compatibility with your compiling platform to a user of your end-result binary on the target platform? Looks like the mother of all it-worked-on-my-machine statements: "Whaddaya mean it has memory allocation errors on your machine? I ran it as if for my totally-different machine at compile-time, so of course it works on yours!"