Yes, I mean, if I declare a const
pointer, it means that I can’t modify the pointer itself, not the data pointed by it. Of course I’m not understanding something basic, so let me explain my point: I thought that const it = mem.split(...)
created a constant pointer to some modifiable data. So mutating the data should not produce an error… What am I missing? Even further, the compiler’s error message seem misleading because it points out that I can cast to const
something that I’m not writing (the self reference automatically added by the compiler as the parameter to the next()
method)
No it returns a value.
Most iterators just return a struct that then lives as a mutable variable on the stack (they don’t return a pointer, but a mutable value).
This struct then has a next method which mutates the fields of that struct, that is only possible through a non const pointer and if you invoke a method on a var that holds a struct, then that method is invoked with a non const pointer allowing the next method to change the fields. If however you declare it as a const then invoking a method on that will mean the method is invoked with a const pointer, thus the method isn’t allowed to change any of the fields (it could however change things those fields point at if they are mutable pointers).
You could create an iterator that just is a struct that holds a pointer to something you can mutate, however that is unusual, likely more complicated than needed and possibly inefficient. Because that pointer needs to point to something and can’t point to memory that is about to become invalid, so that would probably require dynamic memory allocation, the passing the iterator value back to the stack to live there, avoids that and gives the iterator a place to live, while it is needed, without needing allocation on the heap.
Thanks. Actually it makes sense now. I’m probably too used to other languages where everything is in the heap… BTW, the note of the compiler is a bit misleading for me, because it’s pointing to some code generated by itself, in a sense
I am not sure if that is the explanation. Because if I remove the mutation, the error still occurs:
pub fn changePath(path: []u8) !void {
std.sys.debug.print(path, .{}); // ✅
// path[0] = '🫠'; // 😱
}
pub fn main() !void {
try changePath("huh.txt");
return;
}
compilation error
src/main.zig:9:20: error: expected type '[]u8', found '*const [7:0]u8'
try changePath("huh.txt");
^~~~~~~~~
src/main.zig:9:20: note: cast discards const qualifier
src/main.zig:3:25: note: parameter type declared here
pub fn changePath(path: []u8) !void {
That’s because string literals are constants. You cannot coerce them to non-const slices of u8.
https://ziglang.org/documentation/0.13.0/#toc-String-Literals-and-Unicode-Code-Point-Literals