Global comptime counter

I am curious whether it is possible to define a global comptime function cntUp() that returns sequential comptime_int each time it is called at comptime. I want to use it as a comptime source of unique IDs.

1 Like

Not really: there are some tricks you could try using with closures over comptime var in the current compiler, but these loopholes are planned to be closed to prevent this: make closure over comptime var a compile error; comptime vars become immutable when they go out of scope · Issue #7396 · ziglang/zig · GitHub

There was also a post a little while ago with some ideas on implementing something like this: C/C++ macro challenge #1: BOOST_PP_COUNTER For example, even if you don’t want to rely on comptime var loopholes, you can still (ab)use properties such as the uniqueness of opaque{} types to at least get unique ID values, although they won’t be sequential.


It’s possible to make some things unique with @src()

1 Like

Similar to opaque{} struct{} gets a unique typeID and it does not waste a byte. I am using it as a unique anchor.

1 Like

We had a whole thread about this: C/C++ macro challenge #1: BOOST_PP_COUNTER

Edit - just saw @ianprime0509’s post on the same thing. Most of the solutions right now are kind of hacky. A builtin would be nice or doing pre-processing on the file during a build step would also be possible. Sequentially replace the text and increment a counter…

1 Like

I like that creating such a global counter is difficult, because so far I haven’t seen a good reason to make such a feature easy within the language, creating and using a global counter like this seems like a bad idea to me.

It seems to me that the want to have things like this may be caused from c/c++-isms like the awful singleton pattern (or things like it), I think the solution is to stop relying on some global order being enforced across an entire source tree that relies on side effects, which in the worst case puts bad constraints on what the compiler is allowed to do in parallel.

If you need a set of things to have unique indizies, it seems better to me to put these things in one place, for example an array and use their array index as that thing that identifies them. Don’t write cute magic code.

I would be much more interested in the question “How can we rewrite something that relies on hacky global comptime counters, to something that is more ziggy”. Don’t bring the hacky c/c++ stuff into another language, that is my opinion on the topic.

1 Like

In most usage scenario we don’t actually need a comptime value. We’d use the counter to generate a sequence for use at runtime. In theory, it should work just as well if we generate it at linktime instead. That would resolve the conflict with incremental compilation.

I imagine it working like this. Instead of counters we have the concept of linktime sets, to which we can add things at comptime:

// @linkSetAdd(comptime T: type, comptime []const name, comptime thing: anytype) T 

const id = @linktimeSetAdd(u8, "Hello world", .{ .random_literal });

We can see if things are in a set:

// @linkSetContains(comptime []const name, comptime thing: anytype) bool 

if (@linktimeSetContains(u8, "Hello world", .{ .random = true })) {
    // do something if a module added .{ random = true } to set

We can also get the size of the set:

// @linkSetSize(comptime []const name) usize 

if (index < @linktimeSetSize(u8, "Hello world")) {
    // do stuff

Behind the scene, these calls get translate to references to variables in a hidden module to be generated automatically by the linker:

const id = @import("linktimeSet(Hello world)").@"add({ .random_literal }): u8";
// ...
if (@import("linktimeSet(Hello world)").@"has({ .random_literal }): bool";
// ...
if (index < @import("linktimeSet(Hello world)").@"size(): usize") {
// ...

I need a comptime source of globally unique IDs of comptime_int type. Global counter is just one way of doing it. It is a pity that Zig or stdlib does not provide any solution.

But why do you need such a thing, for what?

I am asking this because I wonder whether this topic is a bit of a XY problem - Wikipedia, you said yourself that there are different ways to solve this, if you share the actual problem, without pre-supposing how it should be solved, then maybe somebody has some solution that is way better.