# Issue with opaque {} in inline for

**URL:** <https://ziggit.dev/t/issue-with-opaque-in-inline-for/17732>\
**Category:** Explain\
**Tags:** language, comptime, type-system\
**Created:** [September 27, 2026, 4:28pm UTC](https://ziggit.dev/t/issue-with-opaque-in-inline-for/17732 "2026-09-27T16:28:01Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![Gornak40](https://ziggit.dev/user_avatar/ziggit.dev/gornak40/32/5091_2.png) [@Gornak40](https://ziggit.dev/u/Gornak40)\
**Post date:** [September 27, 2026, 4:28pm UTC](https://ziggit.dev/t/issue-with-opaque-in-inline-for/17732/1 "2026-09-27T16:28:01Z")

</div>

I know that `opaque {}` types are assigned unique identifiers for different literals. I’m wondering why a literal inside `inline for` loop is reused?

In this code snippet `foo()` returns equal type ids, while `bar()` returns distinct:

```zig
const std = @import("std");

fn foo(comptime n: usize) []const type {
    comptime var a: [n]type = undefined;
    inline for (&a) |*t|
        t.* = opaque {};
    return &a;
}

fn bar() []const type {
    return &.{opaque {}, opaque {}, opaque {}};
}

pub fn main() void {
    const f = comptime foo(3);
    const b = comptime bar();
    inline for (f, b) |i, j|
        std.debug.print("foo:{} bar:{}\n", .{i, j});
}

```

Is there any way to create comptime array of n distinct `opaque {}` types?

---

<div class="post-metadata">

**Author:** ![pasta](https://ziggit.dev/user_avatar/ziggit.dev/pasta/32/6273_2.png) [@pasta](https://ziggit.dev/u/pasta)\
**Post date:** [September 27, 2026, 4:30pm UTC](https://ziggit.dev/t/issue-with-opaque-in-inline-for/17732/2 "2026-09-27T16:30:09Z")

</div>

Out of sheer curiosity, why do you need this?

---

<div class="post-metadata">

**Author:** ![rpkak](https://ziggit.dev/letter_avatar_proxy/v4/letter/r/a4c791/32.png) [@rpkak](https://ziggit.dev/u/rpkak)\
**Post date:** [September 27, 2026, 4:34pm UTC](https://ziggit.dev/t/issue-with-opaque-in-inline-for/17732/3 "2026-09-27T16:34:22Z")

</div>

You can use something in the `opaque {}`, which changes every iteration:

```zig
fn foo(comptime n: usize) []const type {
    comptime var a: [n]type = undefined;
    inline for (&a, 0..) |*t, i| {
        t.* = opaque {
            comptime {
                _ = i;
            }
        };
    }
    return &a;
}

```

---

<div class="post-metadata">

**Author:** ![Gornak40](https://ziggit.dev/user_avatar/ziggit.dev/gornak40/32/5091_2.png) [@Gornak40](https://ziggit.dev/u/Gornak40)\
**Post date:** [September 27, 2026, 4:34pm UTC](https://ziggit.dev/t/issue-with-opaque-in-inline-for/17732/4 "2026-09-27T16:34:53Z")

</div>

> [@pasta](#):
>
> Out of sheer curiosity, why do you need this?

I am working on my own [ECS](https://en.wikipedia.org/wiki/Entity_component_system) library that stores all data in static fields of wrapper structs by design. I need a way to ensure that the wrapper function returns a unique type for each user-defined type, so that static fields are not reused. I’m trying to achieve this by using `opaque {}` as a field.

---

<div class="post-metadata">

**Author:** ![Gornak40](https://ziggit.dev/user_avatar/ziggit.dev/gornak40/32/5091_2.png) [@Gornak40](https://ziggit.dev/u/Gornak40)\
**Post date:** [September 27, 2026, 4:37pm UTC](https://ziggit.dev/t/issue-with-opaque-in-inline-for/17732/5 "2026-09-27T16:37:18Z")

</div>

This will work if `foo()` is called only once, but I’d like to get globally unique opaques.

---

<div class="post-metadata">

**Author:** ![alanza](https://ziggit.dev/user_avatar/ziggit.dev/alanza/32/6006_2.png) [@alanza](https://ziggit.dev/u/alanza)\
**Post date:** [September 27, 2026, 4:58pm UTC](https://ziggit.dev/t/issue-with-opaque-in-inline-for/17732/6 "2026-09-27T16:58:12Z")

</div>

Then move the `comptime var` to the scope at which it needs to be unique.

---

<div class="post-metadata">

**Author:** ![castholm](https://ziggit.dev/user_avatar/ziggit.dev/castholm/32/1330_2.png) [@castholm](https://ziggit.dev/u/castholm)\
**Post date:** [September 27, 2026, 5:49pm UTC](https://ziggit.dev/t/issue-with-opaque-in-inline-for/17732/7 "2026-09-27T17:49:41Z")

</div>

Whether or not two namespaces (`struct`, `enum`, `union` or `opaque`) are equivalent is based on the AST nodes they capture. If you have written `opaque {}` on line 7, column 9, then every usage of that exact span of source text is going to reference the exact same namespace. To get a unique namespace, the namespace needs to capture a unique AST node. This is described in more detail [in the 0.12.0 release notes under Namespace Type Equivalence](https://ziglang.org/download/0.12.0/release-notes.html#Namespace-Type-Equivalence) (though it should probably be added to the langref too).

As you noted with @rpkak’s solution, it isn’t enough to just capture a loop index since that would only make each element distinct. To make each call to `foo` distinct you need to capture an AST node unique to the function call. There is no way to declare this “unique thing” entirely from the inside of your function; it must be passed as a parameter by the caller:

```zig
const std = @import("std");

fn foo(comptime n: usize, comptime brand: anytype) []const type {
    // I like to call this parameter used solely as an AST capture a "brand",
    // a term borrowed from a similar concept in TypeScript.
    return comptime a: {
        var a: [n]type = undefined;
        for (&a, 0..) |*t, i| t.* = opaque {
            comptime {
                _ = brand; // unique per function call (if the caller behaves)
                _ = i; // unique per iteration
            }
        };
        break :a &a;
    };
}

pub fn main() void {
    const fa = comptime foo(3, opaque {}); // or '@src()' or anything unique
    const fb = comptime foo(3, opaque {});
    inline for (fa, fb) |i, j|
        std.debug.print("fa:{} fb:{}\n", .{ i, j });
}

```

```zig
fa:z.foo __opaque_687 fb:z.foo__ opaque_691
fa:z.foo __opaque_688 fb:z.foo__ opaque_692
fa:z.foo __opaque_689 fb:z.foo__ opaque_693

```

`opaque {}` or `@src()` are good candidates for “brands”, but anything unique works (and you might want to throw in comptime assertions to help guide your users toward passing a value likely to be unique, instead of e.g. `1` or `"abc"`). And yes, this means that a naughty caller could do e.g.

```zig
const x = opaque {};
const fa = comptime foo(3, x);
const fb = comptime foo(3, x);
inline for (fa, fb) |a, b| assert(a == b);

```

but that’s their problem to worry about, not yours.

---

<div class="post-metadata">

**Author:** ![Gornak40](https://ziggit.dev/user_avatar/ziggit.dev/gornak40/32/5091_2.png) [@Gornak40](https://ziggit.dev/u/Gornak40)\
**Post date:** [September 27, 2026, 6:19pm UTC](https://ziggit.dev/t/issue-with-opaque-in-inline-for/17732/8 "2026-09-27T18:19:50Z")

</div>

A simple and elegant solution. Thank you! 🙂
