# String handling in comptime functions

**URL:** <https://ziggit.dev/t/string-handling-in-comptime-functions/6703>\
**Category:** Help\
**Tags:** language\
**Created:** [November 5, 2024, 4:51pm UTC](https://ziggit.dev/t/string-handling-in-comptime-functions/6703 "2024-11-05T16:51:40Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![nurpax](https://ziggit.dev/user_avatar/ziggit.dev/nurpax/32/1217_2.png) [@nurpax](https://ziggit.dev/u/nurpax)\
**Post date:** [November 5, 2024, 4:51pm UTC](https://ziggit.dev/t/string-handling-in-comptime-functions/6703/1 "2024-11-05T16:51:40Z")

</div>

Hi!

I’m drawing blanks trying to write a comptime functions to return a zero-terminated string of a typename. For example, for a string `"ldtk.Scene"` it’d return just `"Scene"`. But I don’t know how to do this. Here’s what I tried:

```zig
pub fn getMetaname(comptime T: type) [:0]const u8 {
    const fullTypeName = @typeName(T);
    var it = std.mem.splitBackwardsAny(u8, fullTypeName, ".");
    const last = it.first();
    var buffer: [128]u8 = undefined;
    @memcpy(buffer[0..last.len], last);
    buffer[last.len] = 0;
    return buffer[0..last.len :0];
}

pub const metaname = getMetaname(LdtkScene);

```

But I get the below error when I use this function:

```zig
src\lua_ldtk_bindings.zig:11:48: error: global variable contains reference to comptime var
    pub const metaname = getMetaname(LdtkScene);

```

Which is true, of course, but I don’t know how to avoid this.

---

<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:** [November 5, 2024, 5:48pm UTC](https://ziggit.dev/t/string-handling-in-comptime-functions/6703/2 "2024-11-05T17:48:50Z")

</div>

[Comptime-Mutable Memory Changes](https://ziggit.dev/t/comptime-mutable-memory-changes/3702) is a very good and thorough summary of what is and isn’t allowed to become runtime-known, but the relevant part is this:

> [@Comptime-Mutable Memory Changes](https://ziggit.dev/t/comptime-mutable-memory-changes/3702/1):
>
> The most likely way for this to manifest is in a function computing a slice at comptime by filling an array. To fix the error, copy your finalized array to a `const` before taking a pointer.

So the easiest fix is probably something like this:

```diff
 pub fn getMetaname(comptime T: type) [:0]const u8 {
     const fullTypeName = @typeName(T);
     var it = std.mem.splitBackwardsAny(u8, fullTypeName, ".");
     const last = it.first();
     var buffer: [128]u8 = undefined;
     @memcpy(buffer[0..last.len], last);
     buffer[last.len] = 0;
- return buffer[0..last.len :0];
+ const copy = buffer[0..last.len :0].*;
+ return &copy;
 }

 pub const metaname = getMetaname(LdtkScene);

```

---

<div class="post-metadata">

**Author:** ![IntegratedQuantum](https://ziggit.dev/user_avatar/ziggit.dev/integratedquantum/32/782_2.png) [@IntegratedQuantum](https://ziggit.dev/u/IntegratedQuantum)\
**Post date:** [November 5, 2024, 5:52pm UTC](https://ziggit.dev/t/string-handling-in-comptime-functions/6703/3 "2024-11-05T17:52:54Z")

</div>

Also note that in this particular case, you don’t need to make a copy, since results of `@typeName` are already null-terminated, and since you take the last characters, they will still be null-terminated. So, something like this should also work:

```zig
return last[0..last.len :0];

```

---

<div class="post-metadata">

**Author:** ![nurpax](https://ziggit.dev/user_avatar/ziggit.dev/nurpax/32/1217_2.png) [@nurpax](https://ziggit.dev/u/nurpax)\
**Post date:** [November 5, 2024, 5:54pm UTC](https://ziggit.dev/t/string-handling-in-comptime-functions/6703/4 "2024-11-05T17:54:15Z")

</div>

Very cool, thanks for the help! I did find that article but I guess I didn’t fully internalize it. I did try something similar to the above copy trick, but couldn’t get it to work.

As for my original problem, I did realize I can write a much simpler version that doesn’t have this problem:

```zig
pub fn getMetaname(comptime T: type) [:0]const u8 {
    const fullTypeName = @typeName(T);
    if (std.mem.lastIndexOf(u8, fullTypeName, ".")) |idx| {
        return fullTypeName[idx + 1 ..];
    }
    return fullTypeName;
}

```

---

<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:** [November 5, 2024, 6:02pm UTC](https://ziggit.dev/t/string-handling-in-comptime-functions/6703/5 "2024-11-05T18:02:38Z")

</div>

One related useful trick worth remembering is that concatenating a `[]const u8` with `++ ""` will return a 0-terminated result:

```zig
fn zeroTerminate(comptime name: []const u8) [:0]const u8 {
    return name ++ "";
}

test {
    const a: []const u8 = &.{ 'd', 'o', 'g' };
    const b: [:0]const u8 = zeroTerminate(a);
    try @import("std").testing.expectEqualSentinel(u8, 0, "dog", b);
}

```

This can be especially useful if you’re constructing types from strings via `@Type`, since things like field names require null terminators.

---

<div class="post-metadata">

**Author:** ![nurpax](https://ziggit.dev/user_avatar/ziggit.dev/nurpax/32/1217_2.png) [@nurpax](https://ziggit.dev/u/nurpax)\
**Post date:** [November 5, 2024, 7:23pm UTC](https://ziggit.dev/t/string-handling-in-comptime-functions/6703/6 "2024-11-05T19:23:13Z")

</div>

> [@castholm](#):
>
> ```zig
> pub fn getMetaname(comptime T: type) [:0]const u8 {
> const fullTypeName = @typeName(T);
> var it = std.mem.splitBackwardsAny(u8, fullTypeName, ".");
> const last = it.first();
> var buffer: [128]u8 = undefined;
> @memcpy(buffer[0..last.len], last);
> buffer[last.len] = 0;
> - return buffer[0..last.len :0];
> + const copy = buffer[0..last.len :0].*;
> + return &copy;
> }
> 
> ```

Oh wait @castholm, this doesn’t seem to build:

```zig
src\lua_common.zig:27:40: error: index syntax required for slice type '[:0]u8'
    const copy = buffer[0..last.len :0].*;
                 ~~~~~~~~~~~~~~~~~~~~~~ ^~

```

Dropping the `.*` part from the copy slice, I get a build error but the error is not shown:

```zig
Build Summary: 10/13 steps succeeded; 1 failed
run transitive failure
└─ run zig2d transitive failure
   └─ zig build-exe zig2d Debug native failure
error: the following build command failed with exit code 1:
C:\Users\janne\dev\zig2d\.zig-cache\o\e15bb8313dbb2af998d110a7f9162efc\build.exe C:\Users\janne\scoop\apps\zig-dev\0.14.0-dev.1820\zig.exe C:\Users\janne\scoop\apps\zig-dev\0.14.0-dev.1820\lib C:\Users\janne\dev\zig2d C:\Users\janne\dev\zig2d\.zig-cache C:\Users\janne\AppData\Local\zig --seed 0x38ebb4af -Z9a358dfc02c21192 run -freference-trace=15

```

I also tried to extend my other version to add a suffix to the returned string, but somehow I don’t seem to have a good grasp on nailing comptime functions:

```zig
pub fn getMetaname(comptime T: type) [:0]const u8 {
    const vec = @import("gfxutil").vec;
    const fullTypeName = @typeName(T);
    if (T == vec.Mat4.T) {
        return "L_Mat4";
    }

    if (std.mem.lastIndexOf(u8, fullTypeName, ".")) |idx| {
        return "L_" ++ fullTypeName[idx + 1 ..];
    }
    return fullTypeName;
}

```

→

```zig
src\lua_common.zig:28:36: error: unable to resolve comptime value
        return "L_" ++ fullTypeName[idx + 1 ..];
                       ~~~~~~~~~~~~^~~~~~~~~~~~
src\lua_common.zig:28:36: note: slice value being concatenated must be comptime-known

```

---

<div class="post-metadata">

**Author:** ![nurpax](https://ziggit.dev/user_avatar/ziggit.dev/nurpax/32/1217_2.png) [@nurpax](https://ziggit.dev/u/nurpax)\
**Post date:** [November 5, 2024, 8:01pm UTC](https://ziggit.dev/t/string-handling-in-comptime-functions/6703/7 "2024-11-05T20:01:21Z")

</div>

Sorry for spamming my own thread. The last version works, it’s just that it must be called like this in a run-time context:

```zig
fn newUserdataWithMetatable(comptime T: type, lua: *Lua) *T {
    const self = lua.newUserdata(ldtk.LdtkScene, 0);
    const meta = comptime lua_common.getMetaname(ldtk.LdtkScene);
    _ = lua.getMetatableRegistry(meta);
    lua.setMetatable(-2);
    return self;
}

```

I was confused because in other contexts, the comptime keyword is not accepted:

```zig
const LdtkScene = struct {
    pub const classname = "LdtkScene";
    pub const metaname = lua_common.getMetaname(ldtk.LdtkScene);
...

```
