# Const pointer semantics

**URL:** <https://ziggit.dev/t/const-pointer-semantics/17178>\
**Category:** Brainstorming\
**Created:** [August 10, 2026, 10:34pm UTC](https://ziggit.dev/t/const-pointer-semantics/17178 "2026-08-10T22:34:34Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![diskpoppy](https://ziggit.dev/letter_avatar_proxy/v4/letter/d/73ab20/32.png) [@diskpoppy](https://ziggit.dev/u/diskpoppy)\
**Post date:** [August 10, 2026, 10:34pm UTC](https://ziggit.dev/t/const-pointer-semantics/17178/1 "2026-08-10T22:34:34Z")

</div>

Consider the following function that I want to be able to use for both `*const Foo` and `*Foo` arguments:

```zig
fn getBar(foo: *const Foo) *Bar {
    //return foo.bar; //errors out
    return @constCast(foo.bar);
}

```

I’m here to argue that the language semantics should be changed so that the `@constCast` here is not needed, and instead any potential `const` mismatch be identified at the call sites instead:

```zig
const foo_v: *Foo = ...;
const foo_c: *const Foo = ...;

const bar_vv: *Bar = getBar(foo_v); //pass
const bar_vc: *Bar = getBar(foo_c); //fail
const bar_cc: *const Bar = getBar(foo_c); //pass
const bar_cv: *const Bar = getBar(foo_v); //pass

```

This would allow the same function to be used for both `const` and `non-const` pointers without compromising const-safety.

`const` in this case is a little bit unintuitive, because it essentially widens the set of possible input of a function, while it does the opposite to the output.

---

<div class="post-metadata">

**Author:** ![Nico792](https://ziggit.dev/user_avatar/ziggit.dev/nico792/32/2439_2.png) [@Nico792](https://ziggit.dev/u/Nico792)\
**Post date:** [August 10, 2026, 11:14pm UTC](https://ziggit.dev/t/const-pointer-semantics/17178/2 "2026-08-10T23:14:58Z")

</div>

Do you have any real usecases where this would help? In my experience I take a `*T` if I change anything in `T` (thus requiring a mutable pointer) and a `*const T` otherwise (allowing both cases), which hasnt let me down yet.

In this vein I do see some use for propagating sentinels, which Ive ran into using `std.mem.cut*` with a `[:0]const u8`.

In general this is already possible with `fn (v: anytype) @TypeOf(v) { ... }`, but its clunky

---

<div class="post-metadata">

**Author:** ![diskpoppy](https://ziggit.dev/letter_avatar_proxy/v4/letter/d/73ab20/32.png) [@diskpoppy](https://ziggit.dev/u/diskpoppy)\
**Post date:** [August 10, 2026, 11:22pm UTC](https://ziggit.dev/t/const-pointer-semantics/17178/3 "2026-08-10T23:22:17Z")

</div>

As for the use case I made the post in the first place because I encountered this in my code:

```zig
    fn getEntity(g: *const Game, id: EntityID) *Entity {
        return @constCast(&g.entities[@intFromEnum(id)]);
    }

```

I’m using this function both in the game logic which takes `*Game` (and assigns it to `*Entity`), and in the renderer which takes `*const Game` (and must assign it to `*const Entity`).

---

<div class="post-metadata">

**Author:** ![Nico792](https://ziggit.dev/user_avatar/ziggit.dev/nico792/32/2439_2.png) [@Nico792](https://ziggit.dev/u/Nico792)\
**Post date:** [August 10, 2026, 11:47pm UTC](https://ziggit.dev/t/const-pointer-semantics/17178/4 "2026-08-10T23:47:54Z")

</div>

The solution for this Ive seen used here and there is to have `fn get()` as well as `fn getConst()` which is mostly fine if the code is a trivial typesafe getter like this imo. Not a fan of the duplication but there isnt a good fix.

To go deeper into your proposal, this would bring the type forwarding system (I think its called RLS) to funtion return types. The immediate problem I see is how you keep sane function signatures, something like `fn fooGetter(*maybeconst Foo) *maybeconst Bar` but then you just have anytype wrapped in a fairly niche blanket. There might be existing issues (id guess on github), you might find something more substantial there than what Im saying here.

---

<div class="post-metadata">

**Author:** ![Naois](https://ziggit.dev/letter_avatar_proxy/v4/letter/n/ec9cab/32.png) [@Naois](https://ziggit.dev/u/Naois)\
**Post date:** [August 11, 2026, 1:54am UTC](https://ziggit.dev/t/const-pointer-semantics/17178/5 "2026-08-11T01:54:05Z")

</div>

I think that what you’re asking here is tantamount to having the language implicitly infer return type. We can certainly argue about whether this is a good idea, but what you’re describing is already possible in zig just by being explicit about the return type.

```zig
const Bar = u8;
const Foo = struct{bar : Bar};

fn getBar(foo : anytype) constp(@TypeOf(foo), Bar) {
    // Add asserts here to ensure foo is *Foo or *const Foo
    return &foo.bar;
}

fn constp(T : type, U : type) type {
    if(@typeInfo(T).pointer.is_const) {
        return *const U;
    } else {
        return *U;
    }
}

test "getBar test" {
    var foo_v = Foo{.bar = 0};
    const foo_c = Foo{.bar = 1};

    const bar_vv : *Bar = getBar(&foo_v); _ = bar_vv; // pass
    const bar_cv : *Bar = getBar(&foo_c); _ = bar_cv; // fail
    const bar_vc : *const Bar = getBar(&foo_v); _ = bar_vc; // pass
    const bar_cc : *const Bar = getBar(&foo_c); _ = bar_cc; // pass
}

```

It looks like there’s an old [github issue](https://github.com/ziglang/zig/issues/447) discussing return type inference which was eventually discarded.

---

<div class="post-metadata">

**Author:** ![diskpoppy](https://ziggit.dev/letter_avatar_proxy/v4/letter/d/73ab20/32.png) [@diskpoppy](https://ziggit.dev/u/diskpoppy)\
**Post date:** [August 11, 2026, 6:40pm UTC](https://ziggit.dev/t/const-pointer-semantics/17178/6 "2026-08-11T18:40:25Z")

</div>

Is the code-gen smart enough to deduplicate those functions (in case they don’t get inlined)?

---

<div class="post-metadata">

**Author:** ![Sze](https://ziggit.dev/user_avatar/ziggit.dev/sze/32/496_2.png) [@Sze](https://ziggit.dev/u/Sze)\
**Post date:** [August 11, 2026, 7:15pm UTC](https://ziggit.dev/t/const-pointer-semantics/17178/7 "2026-08-11T19:15:14Z")

</div>

> [@Is it possible to apply const on return result adaptively?](https://ziggit.dev/t/is-it-possible-to-apply-const-on-return-result-adaptively/3008/9):
>
> Edited - see post 9 for clarification: [Is it possible to apply const on return result adaptively? - #11 by AndrewCodeDev](https://ziggit.dev/t/is-it-possible-to-apply-const-on-return-result-adaptively/3008/11) Using @This() directly leads to conflicts regarding the member function deduction, but this can be bypassed by using anytype. The rest of the critique and observations are valid, but it is not impossible to achieve what OP was looking for. The problem you’re running into is the specification of the @This() argument because it doesn’t split hairs - it’s either const or not …

---

<div class="post-metadata">

**Author:** ![gwenzek](https://ziggit.dev/user_avatar/ziggit.dev/gwenzek/32/8137_2.png) [@gwenzek](https://ziggit.dev/u/gwenzek)\
**Post date:** [August 11, 2026, 7:57pm UTC](https://ziggit.dev/t/const-pointer-semantics/17178/8 "2026-08-11T19:57:19Z")

</div>

`std.BoundedArray` used to work like this:

[Zig Documentation](https://ziglang.org/documentation/0.14.0/std/#std.bounded_array.BoundedArrayAligned.slice)

It has been removed from std, but the structure and the pattern are still useful

---

<div class="post-metadata">

**Author:** ![Naois](https://ziggit.dev/letter_avatar_proxy/v4/letter/n/ec9cab/32.png) [@Naois](https://ziggit.dev/u/Naois)\
**Post date:** [August 13, 2026, 6:53am UTC](https://ziggit.dev/t/const-pointer-semantics/17178/9 "2026-08-13T06:53:30Z")

</div>

[Doesn’t look like it.](https://godbolt.org/z/dWeM34v7n)

---

<div class="post-metadata">

**Author:** ![dpirch](https://ziggit.dev/user_avatar/ziggit.dev/dpirch/32/5321_2.png) [@dpirch](https://ziggit.dev/u/dpirch)\
**Post date:** [August 13, 2026, 8:24am UTC](https://ziggit.dev/t/const-pointer-semantics/17178/10 "2026-08-13T08:24:36Z")

</div>

Btw, this is essentially the same problem that C used to have with functions like `char *strchr( const char *str, int ch)` which silently removed the `const` of the passed string when it was returned.

C solved this in C23 with type-generic macro wrappers, see [N3020](https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3020.pdf).

I guess the Zig equivalent to this are `@typeInfo` switches like @Naois suggested. The biggest annoyance with these comptime-generated return types in practice is that ZLS usually doesn’t understand them, and you lose code completion support in the IDE for the result (have not tested it for this case).

---

<div class="post-metadata">

**Author:** ![gwenzek](https://ziggit.dev/user_avatar/ziggit.dev/gwenzek/32/8137_2.png) [@gwenzek](https://ziggit.dev/u/gwenzek)\
**Post date:** [August 14, 2026, 4:39am UTC](https://ziggit.dev/t/const-pointer-semantics/17178/11 "2026-08-14T04:39:41Z")

</div>

Hear me out:

```zig
fn slice(x: *|ptr_attr|BoundedArray) []ptr_attr T {
    return x.buffer[0..x.len];
}

```
