Skip to content

@typeName returns struct definition for tuples #23292

Closed as not planned
Closed as not planned

Description

@TheArchitect4855

Zig Version

0.15.0-dev.64+2a4e06bcb

Steps to Reproduce and Observed Behavior

Compiling and running the following source will reproduce the unexpected behaviour:

const std = @import("std");

const Foo = struct {f32};
const Bar = struct {f: f32};

pub fn main() void {
    const foo = @typeName(Foo);
    const bar = @typeName(Bar);
    std.debug.print("{s}\n{s}\n", .{foo, bar});
}

Output when run:

struct { f32 }
test.Bar

Expected Behavior

The tuple struct should be named, just like a regular struct. Expected output:

test.Foo
test.Bar

I first noticed this bug in 0.14. I would expect that @typeName returns the name of the tuple, instead of its definition. Some motivation as to why this matters for me: I'm writing an ECS and I want the end-user to be able to use any type for a component. Thus, I need an ID that is unique per-type at runtime. Since Zig does not have a type ID builtin, I figured @typeName should do the trick. This works perfectly for structs, but not for tuple structs.

Activity

  1. added
    bugObserved behavior contradicts documented or intended behavior
    on Mar 18, 2025
  2. tauoverpi commented on Mar 18, 2025

    @tauoverpi
    Contributor

    see #19858 (comment) on generating a type ID. Note that @typeName is not a reliable source for IDs at all.

    $ tree
    .
    ├── a
    │   └── b.zig
    └── b.zig
    
    2 directories, 2 files
    $ zig build-obj --dep foo -Mroot=b.zig -Mfoo=a/b.zig
    b.zig:5:5: error: found compile log statement
        @compileLog(@typeName(Foo));
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    Compile Log Output:
    @as(*const [5:0]u8, "b.Foo")
    @as(*const [5:0]u8, "b.Foo")
    $ cat b.zig
    const Bar = @import("foo").Foo;
    const Foo = opaque {};
    
    comptime {
        @compileLog(@typeName(Foo));
        @compileLog(@typeName(Bar));
    }
    

    Also, do you really need a type ID or can you require that the user must specify all components they wish to use upfront then take a MultiArrayList approach?

  3. nektro commented on Mar 18, 2025

    @nektro
    Contributor

    this behavior is likely expected because tuples exhibit structural equality and are not unique to the declaration where theyre defined.

  4. mlugg commented on Mar 18, 2025

    @mlugg
    Member

    Working as intended.

    Please refrain from using @typeName to create type IDs. The builtin is implementation-defined, currently unstable in practice, and can return the same name for distinct types in many situations. It's not entirely clear whether it will even remain in the language.

  5. TheArchitect4855 commented on Mar 19, 2025

    @TheArchitect4855
    Author

    I think this raises a deeper issue: It would be really cool if Zig had a way to uniquely identify named types at runtime. The recommended way of generating a type ID does not actually work: if I have two separate tuple structs with the same definition, they generate the same type ID. While there is an argument to be made that this is intended because the types are the same, I think it is also totally reasonable to want differently-named types to have different IDs.

    For now, I think I'll just add a constant u64 field for a "unique ID", but obviously this is flaky and error-prone. imho, a @typeId builtin or similar should be more seriously considered.

    Update: Adding an ID field is not actually possible! Tuples do not allow declarations.

  6. linusg commented on Mar 19, 2025

    @linusg
    Collaborator

    Please refrain from using @typeName to create type IDs.

    How else would you recommend doing safety-checked any-pointer-to-known-type casting? This is something people rely on in the wild: https://github.com/ikskuh/any-pointer (I'm using this to implement ECMAScript's [[HostDefined]] fields in Kiesel)

  7. nektro commented on Mar 19, 2025

    @nektro
    Contributor

    @tauoverpi's comment links to code that can be used to generate type ids. are there ways this falls short for you?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugObserved behavior contradicts documented or intended behavior

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions