Immutability by default

Based on OP’s idea, var s1: []u8 should result in immutable elements.
I think what you want most of the time is const s1: []var u8.
(Note that the above discussion is all based on OP’s hypothetical syntax.)

Most of the time we don’t need the pointer itself to be mutable; we need the elements the pointer points to to be mutable.

The var/const at the beginning defines s1 mutability, not what it points to

Using what’s in Zig right now:

const a: []u8       // constant pointer to mutable elements
  var b: []u8       // mutable pointer  to mutable elements
const c: []const u8 // constant pointer to constant elements
  var d: []const u8 // mutable pointer  to constant elements


a = ... // not allowed, a is constant
b = ... // allowed, b is mutable
c = ... // not allowed, c is constant
d = ... // allowed, d is mutable

a[0] = 0 // allowed, a points to mutable data
b[0] = 0 // allowed, b points to mutable data
c[0] = 0 // not allowed, c points to constant data
d[0] = 0 // not allowed, d points to constant data

This proposal only changes []u8 to constant elements and introduces []var u8 to be mutable elements

2 Likes

In its current form const feels like just a way to tell what value was comptime computed and can’t be changed. At least its the root of it. It later spreads around by the fact what marking pointer as const allows you to pass comptime know values to it which makes code more reusable.

As an example string literals are comptime generated values and thus have const pointer to them. If you want to make some kind of string processing utility you will mark all pointers const to allow using string literals in it.

I never really had bugs related to constness in its current implementation so I don’t really think switching it around would help. There are languages which don’t even have knowledge of const pointers (jai) and they seem to work pretty well.

Since its mostly feature used to protect user from modifying data in region of memory marked as const it always crashes a program it you do that so its easy to catch.

1 Like

If that’s the full truth, then the answer to my original question is: “yes”. I understand the OP, and am thankful for the reiterations, but they aren’t necessary. I just wondered whether the new idea of changing []u8 to mean []const u8, regardless of whether the variable itself was const or var. In the original post, everything was declared const, which made me wonder if that was suppose to be special treatment. But I think it only makes sense to always interpret []u8 to mean []const u8 (and, by implication, if you want mutable elements, then, regardless of whether the array is a cost or var, you’d have to declare []var u8. If so, I agree that this is interesting, and would not feel anchored to the C heritage. The departure from that heritage would be ziggish.

2 Likes

In addition, a pointer-to-const, doesn’t require the data it points to to be declared with const, so *T would mean “no requirement”. And a pointer-to-var does require the data it points to to be declared with var (if not on the heap), so *var T would mean “declared with var requirement”. I think it beautifully makes sense.

5 Likes

I think this is a skill issue. Immutability by default is safer, but I think this is just one of those pre established things that C got right. It’s called CV-qualifiers and has long history. You could replace them with MV-qualifiers (mutable, volatile) instead, but it is quiche-eating behavior. Just go do rust if you want hand holding and guarantees, I think Zig is very well balanced between improved pointer ergonomics against footguns and not mixing things up for no apparent purpose such as default const-ing all pointers.

That’s misleading. The hardware has no preference as to how you configure your GDT. You could say you have to “explicitly” set writable to 1, but that isn’t really an argument towards defaulting to read-only in your programming language, you have to “explicitly” set it to 0 as well.

1 Like

I’am also in favor of const as default but isn’t this allot of work to reimplement? As in the biggest PR ever made in the history of Zig or am I wrong and it’s a idiomatic change and straight forward to get right in the zig front end compiler?

2 Likes

Some excellent technical arguments. Got me convinced!

18 Likes

I don’t think the change to the front end itself would be too bad, it’s just a syntactic change the way I understand this proposal.

The PR would be pretty big though, mostly because Zig is self-hosting, and so the new syntax would need to be applied all over the codebase of the compiler itself and the std. But even that would be mostly grunt work (changing all []T to []var T and all []const T to []T) and not too cognitively taxing. It’d be big as in many lines changed, but not complicated I think.


All in all, I also think there is merit to the proposal, especially since PRO has been removed, as mentioned above. I do shudder at the thought of having to go through all my pointers and changing them, but that would just be a one-off and it’s what I signed up for by choosing a language whose creator made it very clear he’s willing to break it from time to time :slightly_smiling_face:

I like it.

5 Likes

At first glance, this change seems like something that zig fmt would be able to automatically migrate like it already does with some straightforward breaking changes between releases.

6 Likes

Nice, so step one would be a fmt PR that would format any zig code to the new ‘zig const default code’ before we call in the compiler guy’s to take a look?

https://codeberg.org/ziglang/zig/src/branch/master/src/fmt.zig Probably out of my league but where do you begin here? I see a fmt struct but then I lose site of where to go next? Was thinking adding a ‘–const’ flag

step one is to get an approval on the language change proposal. which i guess makes step zero getting permission to make such a proposal.

I am a strong believer proposals should be written in zig code including some test blocks :slight_smile:

well in that case get to work! for an entirely cosmetic change like this it shouldn’t take too long :slight_smile:

I simply do not see the actual benefits here that make this worth it.
The arguments in its favor seem subjective and more like a solution looking for a problem, not any real-world problem that needs a solution.

6 Likes

This is such a great point, I never directly thought of const pointers as being more relaxed/less specific than mutable pointers

1 Like

What about if we translate the proposal into regex, then we can check if we mist something so we have a unambiguous definition to put in Andrew his mailbox?

sed -E -e 's/\[\]const[[:space:]]+([a-zA-Z_][a-zA-Z0-9_.]*)/[] \1/g' \
       -e 's/\[\]([a-zA-Z_][a-zA-Z0-9_.]*)/[]var \1/g' test.zig

I know it going to be a more complex regex then this :stuck_out_tongue: but effort is to make sure we are all on the same page here.

My own familiarity the traditional style of mutable pointers aside… (Not a sentiment that seems to garner much sympathy here it seems :sweat_smile:)

This change does initially seem to me like one that would be terribly ergonomic, and does not seem to offer any concrete benefit. (Am I missing something here, aside from the vague ideal that proponents of the idea say default immutability might be safer or more consistent in some way?)

Are there particular situations where the change would, for example, prevent a common class of programmer mistakes or application bugs, allow for better compiler optimization or performance, or otherwise increase Zig’s ability to approach its intended set of use cases? If so, what might some of these be?

Forgive me if this is seen as raining on the parade somewhat, or I have mistakenly taken a purely theoretical conversation too seriously; it’s just that perhaps a little more evidence-based deliberation is in order before opinions start to be formed one way or the other on this.

I am wholly open to being convinced otherwise if there is more to this picture that I’m not getting. Maybe an example of an existing location in the standard library or some other codebase of some repute that would be improved by default constness?

3 Likes

Do you mean “address of” operator & would produce a const pointer? How would that work?

const slice: []var u8 = @varCast(&buffer);

Disgusting.