# What is cast discards const qualifier error

**URL:** <https://ziggit.dev/t/what-is-cast-discards-const-qualifier-error/6159>\
**Category:** Explain\
**Tags:** language\
**Created:** [September 27, 2024, 4:31am UTC](https://ziggit.dev/t/what-is-cast-discards-const-qualifier-error/6159 "2024-09-27T04:31:24Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![finlaydotb](https://ziggit.dev/user_avatar/ziggit.dev/finlaydotb/32/3462_2.png) [@finlaydotb](https://ziggit.dev/u/finlaydotb)\
**Post date:** [September 27, 2024, 4:31am UTC](https://ziggit.dev/t/what-is-cast-discards-const-qualifier-error/6159/1 "2024-09-27T04:31:24Z")

</div>

I run into various cases where I encounter the error

> cast discards const qualifier

In most cases I usually need to change from var to const or vice versa.

But I am not sure I actually understand what the error message really mean because most of the time I am not performing explicit cast, and the line of code the compiler points at in the error, is usually not one that has a cast also.

Would be nice to actually know what the compiler means when it errors with “cast discards const qualifier”.

---

<div class="post-metadata">

**Author:** ![b33j0r](https://ziggit.dev/user_avatar/ziggit.dev/b33j0r/32/3346_2.png) [@b33j0r](https://ziggit.dev/u/b33j0r)\
**Post date:** [September 27, 2024, 5:31am UTC](https://ziggit.dev/t/what-is-cast-discards-const-qualifier-error/6159/2 "2024-09-27T05:31:43Z")

</div>

Hi, it sounds like you almost understand what’s going on, actually. There’s just an implicit cast or type coercion going on somewhere; this implicit cast might be fine and convenient for reading the const’s value, but not for mutating it.

I often see this when I write something like

```zig
pub fn changePath(path: []u8) !void {
    sys.debug.print(path, .{}); // ✅
    path[0] = '🫠'; // 😱
}

pub fn main() !void {
    try changePath("huh.txt");
}

```

The key to reading the debug message is to look at which types it says it found, and then look at the arrows in the excerpted code.

```zig
src/main.zig:10:20: error: expected type '[]u8', found '*const [7:0]u8'
    try changePath("huh.txt");
                   ^ ~~~~~~~~
src/main.zig:10:20: note: cast discards const qualifier
src/main.zig:5:25: note: parameter type declared here
pub fn changePath(path: []u8) !void {

```

If you imagine the arrows being a box where your bytes are, it’s telling you that only a certain type fits in that box, after all the explicit casting and coercion rules have been applied. You have to change the type it expects, or what you are giving it.

PS: to answer your question more directly, it’s telling you it tried to erase the const (coercion/discard qualifier) so you could pass that to the function’s signature, since the types are almost compatible for reading. But then something mutates it in that scope or even nested deeper, and the compiler has to abandon that assumption of const.

---

<div class="post-metadata">

**Author:** ![dee0xeed](https://ziggit.dev/letter_avatar_proxy/v4/letter/d/3ab097/32.png) [@dee0xeed](https://ziggit.dev/u/dee0xeed)\
**Post date:** [September 27, 2024, 6:47am UTC](https://ziggit.dev/t/what-is-cast-discards-const-qualifier-error/6159/3 "2024-09-27T06:47:38Z")

</div>

The following is not an explanation, rather some little investigation.  
Trying to compile this

```zig
const std = @import("std");
const S = packed struct {a: u8, b: u8, c: u8, d: u8};
pub fn main() void {
    const buf = [4]u8{1,2,3,4};
    const p: *S = @ptrCast(@alignCast(&buf));
    std.debug.print("s = {any}\n", .{ p.*});
}

```

throws

```zig
2.zig:9:19: error: @ptrCast discards const qualifier
    const p: *S = @ptrCast(@alignCast(&buf));
                  ^ ~~~~~~~~~~~~~~~~~~~~~~~~~
2.zig:9:19: note: use @constCast to discard const qualifier

```

Compare `error` and `note`!!!  
Together they look a bit enigmatic, don’t they?

We can fix the program by two ways.

## follow compiler advice, i.e

```zig
const p: *S = @constCast(@ptrCast(@alignCast(&buf)));

```

## make `buf` mutable, i.e

```zig
var buf = [4]u8{1,2,3,4};

```

Now to original version.  
As I understand in this case error is because `buf` is immutable,  
but we cast it’s address to some pointer and we can potentially change  
`buf` content via this pointer and

- `constCast()` makes the pointer to be pointer to immutable data
- making `buf` mutable… well, just makes it mutable, so the pointer is ok.

---

<div class="post-metadata">

**Author:** ![jeffective](https://ziggit.dev/user_avatar/ziggit.dev/jeffective/32/3116_2.png) [@jeffective](https://ziggit.dev/u/jeffective)\
**Post date:** [September 27, 2024, 7:14am UTC](https://ziggit.dev/t/what-is-cast-discards-const-qualifier-error/6159/5 "2024-09-27T07:14:04Z")

</div>

Things to remember:

1. All function parameters in zig are constant.
2. Function parameters can be pointers (memory locations)
3. Function parameters can be value (contents of memory)
4. You can have pointers to constant memory.
5. The compiler will check to make sure you do not try to use constant memory where you should be using modifiable memory (illegal cast of const to var)
6. The concept of constant memory enables a lot of optimizations (lets you re-use memory because you know you arent going to modify it!)

```zig
//! Run this file using: zig test path_to_this_file.zig
//!
//! We expect the first test to succeed and the second test to produce the const cast compile error.

const std = @import("std");
// All function parameters are constant in zig.

/// add one to the number I pass into this function by reference.
/// The reference (location in memory) is constant. But the contents of the memory
/// at that location can change.
pub fn addOneInPlace(num: *u8) void {
    num.* += 1;
}

/// The number I am passing into this function is constant and a new number is returned.
pub fn addOne(num: u8) u8 {
    return num + 1;
}

/// The location in memory is constant and the contents of the memory is constant.
pub fn addOneUsingReference(num: *const u8) u8 {
    return num.* + 1;
}

test "add one correctly" {
    var modifiable_number: u8 = 1;
    addOneInPlace(&modifiable_number);
    try std.testing.expect(modifiable_number == 2);

    const constant_number: u8 = 1;
    const new_constant_number: u8 = addOne(constant_number);
    try std.testing.expect(new_constant_number == 2);

    const new_constant_number_again = addOneUsingReference(&constant_number);
    try std.testing.expect(new_constant_number_again == 2);
}

test "add one illegally" {
    const constant_number: u8 = 1;
    addOneInPlace(&constant_number); // compile error here!
    try std.testing.expect(constant_number == 1);
}

```

```zig
jeff@jeff-debian:~/repos/zecm$ zig test experimental/test.zig 
experimental/test.zig:40:19: error: expected type '*u8', found '*const u8'
    addOneInPlace(&constant_number); // compile error here!
                  ^ ~~~~~~~~~~~~~~~
experimental/test.zig:40:19: note: cast discards const qualifier
experimental/test.zig:11:27: note: parameter type declared here
pub fn addOneInPlace(num: *u8) void {
                          ^~~

```

---

<div class="post-metadata">

**Author:** ![dee0xeed](https://ziggit.dev/letter_avatar_proxy/v4/letter/d/3ab097/32.png) [@dee0xeed](https://ziggit.dev/u/dee0xeed)\
**Post date:** [September 27, 2024, 7:18am UTC](https://ziggit.dev/t/what-is-cast-discards-const-qualifier-error/6159/6 "2024-09-27T07:18:12Z")

</div>

> [@jeffective](#):
>
> You can have pointers to constant memory

I guess this is more or less about my example.

---

<div class="post-metadata">

**Author:** ![LucasSantos91](https://ziggit.dev/user_avatar/ziggit.dev/lucassantos91/32/440_2.png) [@LucasSantos91](https://ziggit.dev/u/LucasSantos91)\
**Post date:** [September 27, 2024, 11:50am UTC](https://ziggit.dev/t/what-is-cast-discards-const-qualifier-error/6159/7 "2024-09-27T11:50:05Z")

</div>

> [@dee0xeed](#):
>
> As I understand in this case error is because `buf` is immutable,  
> but we cast it’s address to some pointer and we can potentially change  
> `buf` content via this pointer

That’s undefined behavior (illegal behavior in Zig lingo). In this case, the compiler suggestion should not be followed. If the underlying buffer is `const` you are never allowed to change it, no matter how many casts and builtins you throw at it.  
Behind the scenes, `const` data can go into the read-only section, which is protected from change by the OS, or it can be baked directly into the code, so it would have no address.  
`@constCast` can ony be used if the pointed-to memory is mutable, but you ended up with a `const` pointer to it.

```zig
fn weirdMutationFunction(ptr: *const u8) void{
  const cast = @constCast(ptr);
  cast.* = 3;
}

fn main() void{
  var buffer: u8 = 0;
  const ptr: *const u8 = &buffer;
  weirdMutationFunction(ptr);
  std.debug.print("{}", .{ptr.*});
}

```

Output: 3

This works because `buffer` is actually mutable, despite what the pointer says.  
Obviously, no one should write code like this. But sometimes you have a callback system or some kind of channel, and it expects a const pointer. So you can give it a const pointer and, at the other end, since you are sure you passed a pointer to mutable data, you can cast away the constness.

---

<div class="post-metadata">

**Author:** ![dee0xeed](https://ziggit.dev/letter_avatar_proxy/v4/letter/d/3ab097/32.png) [@dee0xeed](https://ziggit.dev/u/dee0xeed)\
**Post date:** [September 27, 2024, 12:30pm UTC](https://ziggit.dev/t/what-is-cast-discards-const-qualifier-error/6159/8 "2024-09-27T12:30:47Z")

</div>

> [@LucasSantos91](#):
>
> That’s undefined behavior (illegal behavior in Zig lingo). In this case, the compiler suggestion should not be followed. If the underlying buffer is `const` you are never allowed to change it, no matter how many casts and builtins you throw at it

I got it.  
Then it comes that my example can not be “fixed”, `buf` becomes mutable,  
either explicitly (`var buf`) or by `@constCast`ing.

---

<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:** [September 27, 2024, 2:02pm UTC](https://ziggit.dev/t/what-is-cast-discards-const-qualifier-error/6159/9 "2024-09-27T14:02:51Z")

</div>

> [@dee0xeed](#):
>
> or by `@constCast`ing

No `@constCast`ing has no effect on the actual mutability of a buffer.

It only allows you to get a mutable pointer and using that mutable pointer on a read only buffer to attempt to change something is illegal and can result in a panic / crash.

---

<div class="post-metadata">

**Author:** ![dee0xeed](https://ziggit.dev/letter_avatar_proxy/v4/letter/d/3ab097/32.png) [@dee0xeed](https://ziggit.dev/u/dee0xeed)\
**Post date:** [September 27, 2024, 2:39pm UTC](https://ziggit.dev/t/what-is-cast-discards-const-qualifier-error/6159/10 "2024-09-27T14:39:03Z")

</div>

> [@Sze](#):
>
> No `@constCast`ing has no effect on the actual mutability of a buffer.

Yes, that’s right, I put it wrong, sorry. I meant that with `const buf` and with `@constCast()` the program **compiles** (and runs) without errors.

- `const buf` and no `@constCast`: `error: @ptrCast discards const qualifier`
- `var buf` and no `@constCast`: ok
- `const buf` and with `@constCast`: also ok

---

<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:** [September 27, 2024, 2:43pm UTC](https://ziggit.dev/t/what-is-cast-discards-const-qualifier-error/6159/11 "2024-09-27T14:43:34Z")

</div>

> [@dee0xeed](#):
>
> `const buf` and with `@constCast`: also ok

It can happen to work, but it still isn’t reliable because the data of the `const buf` can be placed into read only memory by the compiler and if that happens the program will crash. That is why you shouldn’t use `@constCast` to remove the const unless you actually know that the buf was declared with `var`.

`@constCast` should only be used when it is unavoidable, here it is clearly avoidable and when you know for certain that the buffer will always be mutable.

Using a `const buf` with `@constCast` will likely cause unexpected panics when the compiler changes and places more immutable things in read-only memory.  
It also can cause logic bugs / undefined behavior because one part of your program claims the memory is immutable while another modifies it.

I guess maybe I misunderstood you a bit, if you meant to use a mutable pointer, without actually modifying anything, but if you aren’t modifying it, then it is better to just use a const pointer instead of casting away the constness and hoping nobody will actually use the mutable pointer for setting new values.

Passing around non const pointers to constant data is a bad practice and only makes sense in very rare corner cases, where you are sure that this particular instance won’t be modified while maybe other ones will be.  
But people who work on such corner cases will be aware of those details.

* * *

Overall telling the compiler this data is constant/immutable and then changing it is a bad idea.

---

<div class="post-metadata">

**Author:** ![dee0xeed](https://ziggit.dev/letter_avatar_proxy/v4/letter/d/3ab097/32.png) [@dee0xeed](https://ziggit.dev/u/dee0xeed)\
**Post date:** [September 27, 2024, 3:02pm UTC](https://ziggit.dev/t/what-is-cast-discards-const-qualifier-error/6159/12 "2024-09-27T15:02:46Z")

</div>

> [@Sze](#):
>
> It can happen to work, but it still isn’t reliable

Ok, I am rephrasing my previous ramblings.  
That program can not be “fixed” in a sense that:

- I can use `var buf`, but what if I really want it to be immutable?
- I can use `@constCast()`, but as you and @LucasSantos91 explained this is not a way to follow and… compiler is a bad adviser in this case.

---

<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:** [September 27, 2024, 3:11pm UTC](https://ziggit.dev/t/what-is-cast-discards-const-qualifier-error/6159/13 "2024-09-27T15:11:04Z")

</div>

> [@dee0xeed](#):
>
> I can use `var buf`, but what if I really want it to be immutable?

Then you use a constant buffer and a pointer to constant data `*const S`:

```zig
const std = @import("std");
const S = packed struct { a: u8, b: u8, c: u8, d: u8 };
pub fn main() void {
    const buf = [4]u8{ 1, 2, 3, 4 };
    const p: *const S = @ptrCast(@alignCast(&buf));
    std.debug.print("s = {any}\n", .{p.*});
}

```

Do you mean something different?

---

<div class="post-metadata">

**Author:** ![dee0xeed](https://ziggit.dev/letter_avatar_proxy/v4/letter/d/3ab097/32.png) [@dee0xeed](https://ziggit.dev/u/dee0xeed)\
**Post date:** [September 27, 2024, 3:12pm UTC](https://ziggit.dev/t/what-is-cast-discards-const-qualifier-error/6159/14 "2024-09-27T15:12:52Z")

</div>

phew!  
here is absolutely legal variant:

```zig
const std = @import("std");
const S = packed struct {a: u8, b: u8, c: u8, d: u8};
pub fn main() void {
    const buf = [4]u8{1,2,3,4};
    const p: *const S = @ptrCast(@alignCast(&buf));
    std.debug.print("s = {any}\n", .{ p.*});
}

```

---

<div class="post-metadata">

**Author:** ![dee0xeed](https://ziggit.dev/letter_avatar_proxy/v4/letter/d/3ab097/32.png) [@dee0xeed](https://ziggit.dev/u/dee0xeed)\
**Post date:** [September 27, 2024, 3:20pm UTC](https://ziggit.dev/t/what-is-cast-discards-const-qualifier-error/6159/15 "2024-09-27T15:20:38Z")

</div>

> [@Sze](#):
>
> Do you mean something different?

No, this is exactly what was needed, immutable pointer to immutable data.  
It was that `note: use @constCast to discard const qualifier` that disoriented me.

---

<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:** [September 27, 2024, 3:28pm UTC](https://ziggit.dev/t/what-is-cast-discards-const-qualifier-error/6159/16 "2024-09-27T15:28:58Z")

</div>

maybe there should be two notes where the first is:  
`note: use a constant slice/pointer or`  
`note: use @constCast to discard const qualifier`

Might make sense to think about the different cases and how the error message could be improved in the compiler, I don’t think the current note is that good, it is quite rare where discarding const is actually the right thing to do.

---

<div class="post-metadata">

**Author:** ![dee0xeed](https://ziggit.dev/letter_avatar_proxy/v4/letter/d/3ab097/32.png) [@dee0xeed](https://ziggit.dev/u/dee0xeed)\
**Post date:** [September 27, 2024, 7:24pm UTC](https://ziggit.dev/t/what-is-cast-discards-const-qualifier-error/6159/17 "2024-09-27T19:24:51Z")

</div>

> [@finlaydotb](#):
>
> I run into various cases where I encounter the error
> 
> > cast discards const qualifier

Could you please share some of these cases?

---

<div class="post-metadata">

**Author:** ![andrewrk](https://ziggit.dev/user_avatar/ziggit.dev/andrewrk/32/7011_2.png) [@andrewrk](https://ziggit.dev/u/andrewrk)\
**Post date:** [September 27, 2024, 8:12pm UTC](https://ziggit.dev/t/what-is-cast-discards-const-qualifier-error/6159/18 "2024-09-27T20:12:33Z")

</div>

> [@dee0xeed](#):
>
> compiler advice

Just to be super clear: it’s a “note”, not a “hint”. So it’s not really a suggestion or advice, it’s just informing the programmer the existence of a relevant language feature.

I’ve been very strict rejecting contributions that add “hints” to the compiler, because in my experience such hints can never be 100% accurate (otherwise they wouldn’t need to be diagnostics, the language would just allow the construct), and so hints are not allowed in compiler diagnostics. They must _inform_ rather than _prescribe_. Similarly, I think this is what good documentation comments do.

---

<div class="post-metadata">

**Author:** ![dee0xeed](https://ziggit.dev/letter_avatar_proxy/v4/letter/d/3ab097/32.png) [@dee0xeed](https://ziggit.dev/u/dee0xeed)\
**Post date:** [September 28, 2024, 9:07am UTC](https://ziggit.dev/t/what-is-cast-discards-const-qualifier-error/6159/19 "2024-09-28T09:07:17Z")

</div>

> [@finlaydotb](#):
>
> But I am not sure I actually understand what the error message really mean because most of the time I am not performing explicit cast, and the line of code the compiler points at in the error, is usually not one that has a cast also

Yes, this may be somewhat confusing.  
But now I understand what compiler complains about for my example with pointer casting at least. Sorry for repetition 🙂 Here is context:

```zig
const buf = [4]u8{1,2,3,4};
const p: *S = @ptrCast(@alignCast(&buf));

```

and here is compiler message:

```plaintext
error: @ptrCast discards const qualifier
const p: *S = @ptrCast(@alignCast(&buf));
              ^ ~~~~~~~~~~~~~~~~~~~~~~~~~

```

Compiler kinda says:

"Hey, man, listen here:

- on the RHS of the assignment you have `&buf`, **a pointer to immutable data** , since you declare `buf` as `const buf` in the line above, don’t you?
- on the LHS of the assignment you have `*S`, **a pointer to mutable data**

You are likely going to do something wrong.  
"

---

<div class="post-metadata">

**Author:** ![stratozero](https://ziggit.dev/user_avatar/ziggit.dev/stratozero/32/3152_2.png) [@stratozero](https://ziggit.dev/u/stratozero)\
**Post date:** [October 31, 2024, 7:17pm UTC](https://ziggit.dev/t/what-is-cast-discards-const-qualifier-error/6159/20 "2024-10-31T19:17:34Z")

</div>

For me one the greatest source of confusion is the fact that some structs’ function takes a mutable pointer to `self`, so, for example, it seems that I can’t invoke `next()` on a `const SplitIterator`. Maybe for some good reason that I haven’t investigated

---

<div class="post-metadata">

**Author:** ![permutationlock](https://ziggit.dev/user_avatar/ziggit.dev/permutationlock/32/9958_2.png) [@permutationlock](https://ziggit.dev/u/permutationlock)\
**Post date:** [October 31, 2024, 7:22pm UTC](https://ziggit.dev/t/what-is-cast-discards-const-qualifier-error/6159/21 "2024-10-31T19:22:56Z")

</div>

When you call `.next()` on an iterator it needs to modify its internal state so that subsequent calls return subsequent elements. If an iterator was `const` it couldn’t iterate.

[Next page](https://ziggit.dev/t/what-is-cast-discards-const-qualifier-error/6159.md?page=2)
