In Zig, a pointer type having a const
qualifier means that you cannot write to the memory which
the address points to using that pointer:
const Foo = struct {
bar: i32,
};
pub fn main() void {
var x = Foo{ .bar = 5 };
const p: *const Foo = &x;
p.bar += 1; // compile error: 'cannot assign to a constant'
}
So a *const T
pointer can be thought of as an immutable reference to T
, the meaning which the programmer takes from the type is “I’m just looking at T, not changing it!”. This is useful because it helps the programmer when reading code to know what state can and can’t change.
Now what happens if the memory which the const
pointer addresses contains another pointer, which is not const
?
const Foo = struct {
bar: *Bar,
};
const Bar = struct {
baz: i32,
};
pub fn main() void {
var bar = Bar{ .baz = 5 };
var foo = Foo{ .bar = &bar };
const p: *const Foo = &foo;
p.bar.baz += 1;
}
This code compiles and runs with no errors!
This arguably contradicts the implied meaning of a *const T
: “I’m just observing T, I won’t touch it!” Of course technically that is the case - but it is changing something else via the constant pointer through a non-const pointer at that location. This is something the programmer might not expect if they have internalized the aforementioned implication of a const
pointer, which (again) is a useful one.
This struct me as something that Rust would be terribly concerned about, so I tried it:
struct Foo<'a> {
bar: &'a mut Bar,
}
struct Bar {
baz: i32,
}
pub fn main() {
let mut bar = Bar { baz: 5 };
let foo = Foo { bar: &mut bar };
let p = &foo;
p.bar.baz += 1;
}
Surprisingly, rust doesn’t have a problem with this code!
Just kidding.
error[E0594]: cannot assign to `p.bar.baz`, which is behind a `&` reference
--> const.rs:13:5
|
13 | p.bar.baz += 1;
| ^^^^^^^^^^^^^^ `p` is a `&` reference, so the data it refers to cannot be written
|
help: consider changing this to be a mutable reference
|
12 | let p = &mut foo;
| +++
I’m not sure how exactly rust enforces this. A simple idea would be to demote all the pointer types of a type behind a const pointer to also be const, but I don’t know how complicated that would be to add to the Zig compiler. Still, I think this is a good semantic for a low-level language to have.