Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Explicit use of the 'var' keyword for pointers and arrays to mutable data #5056

Closed
XaviDCR92 opened this issue Apr 15, 2020 · 11 comments
Closed
Labels
proposal This issue suggests modifications. If it also has the "accepted" label then it is planned.
Milestone

Comments

@XaviDCR92
Copy link

As of zig 0.6.0, pointers can be defined as *type or *const type, whereas array (when used as function parameters) can be defined as []type or []const type. This means they are mutable by default, similarly to C and C++.

However, experience has proven default mutability might cause bugs and/or unexpected behaviour, especially when pointers (or pointers to pointers, etc.) are involved. We must take into we programmers are lazy and often prefer omitting a few keystrokes (especially among beginners) over adding zero-cost safety. Therefore, I want to make a proposal that aims to be consistent with the rest of the Zig language:

  • Use *var type for pointers to mutable data and []var type for arrays to mutable data.
  • Keep existing rules for pointers/arrays to immutable data, *const type / []const type.

IMHO, this style is consistent with the existing way of defining variables in Zig via the var / const keywords. Whereas default immutability could be instead applied (as in Rust), forcing the user to choose either const or var still makes the intention clear for the reader and fits better with the language.

P.S.: while discussing this proposal on IRC, some users preferred using mut over var for this specific situation, as it would cause confusion when varis used as a type. However, according to #4820 var would be renamed to anytype, avoiding such confusion.

@XaviDCR92 XaviDCR92 changed the title Explicit use of the 'var' keyword for mutable pointers and arrays Explicit use of the 'var' keyword for pointers and arrays to mutable data Apr 15, 2020
@shakesoda
Copy link

per my comments on irc, i don't have any particular interest in throwing more keywords all over my code, but i'm not so opposed to this if it's a reversal of default mutability to default immutability

@nycex
Copy link
Contributor

nycex commented Apr 15, 2020

In my opinion, the best solution would be immutability be default and *mut/[]mut for mutability.

Pros

  • default is most restrictive
  • doesn't cause confusion with other uses of var

Cons

  • inconsistency in regards to zig's const and var variable declaration
  • additional keyword

Edit: After thinking about it, with #4820 being accepted, I think *var/[]var is better than *mut/[]mut.

@foobles
Copy link
Contributor

foobles commented Apr 16, 2020

@nycex It is consistent

var declares mutable variables, const declares constant.
*var T is a pointer to mutable, *const T is a pointer to constant.

@nycex
Copy link
Contributor

nycex commented Apr 16, 2020

The Pros and Cons I listed are for *mut/[]mut.

Forcing the user to add const or var is the most consistent, while being bad for readability.
Immutability be default with adding var for mutable pointers would be as readable and as consistent as status quo, but restrictive by default (which I think is the better approach than mutability by default).

@XaviDCR92
Copy link
Author

XaviDCR92 commented Apr 16, 2020

@theInkSquid I think @nycex was referring to mut being inconsistent with the language. I guess we all think var makes much more sense given how the Zig language works.

To be honest, I would also prefer default immutability for pointers and arrays, as the risk for non const-correct code increases with pointers to pointers and so on, and currently securing them harms readability. For example, **Foo can be modified in at least two possible ways, and securing it would require *const *const Foo, which is far less readable. If default immutability was preferred, a pointer to mutable pointer to mutable data would be *var *var Foo, which makes clear the intention from the author, and the most readable solution (**Foo) would also be the most secure.

But should the Zig community refuse to go back to default immutability for whatever reason, forcing the user to choose between var and const still brings a good balance between safety and consistency given the current status of the language. Whichever method is used, I just would like Zig to learn from some of the unsafe design decisions that C and C++ made so it can be both a safe and feasible alternative to these.

Edit: fixed description for *var *var Foo.

@mikdusan
Copy link
Member

mikdusan commented Apr 16, 2020

consider this example to avoid a copy; we can add mut modifier support for parameters and be consistent with a default-immutable language change:

std.mem.indexOfScalarPos()

// (current zig)

pub fn indexOfScalarPos(comptime T: type, slice: []const T, start_index: usize, value: T) ?usize {
    var i: usize = start_index;
    while (i < slice.len) : (i += 1) {
        if (slice[i] == value) return i;
    }
    return null;
}

// default-immutable
// notice here that the start_index can now be immediately used as induction variable
// this example also requires some syntax support for a storage modifier on the parameter itself

pub fn indexOfScalarPos(comptime T: type, slice: []T, mut i: usize, value: T) ?usize {
    while (i < slice.len) : (i += 1) {
        if (slice[i] == value) return i;
    }
    return null;
}

edit: removed a mut modifier to slice

@XaviDCR92
Copy link
Author

@mikdusan I'm not sure why the mut would be needed for slice, as it is not modified by indexOfScalarPos. Personally, I already like Zig's way of treating all function parameters as read-only, so I would not modify that part. I guess the compiler still needs to make a copy of the parameter if it has to be modified by the function anyway, so I think it's a good idea to make that explicit. Otherwise, I think the var qualifier would fit better here rather than mut, as it would follow the same convention used to define variables.
Anyway, the point of this issue is not addressed to function parameters (which are already immutable by default, and I think they should stay this way), but to pointers and arrays, where it can be a source of bugs.

@mikdusan
Copy link
Member

not sure why the mut would be needed for slice

you're right it's not needed. edited.

@mikdusan
Copy link
Member

the point of this issue is not addressed to function parameters

right, however with our current syntax we cannot do what is shown. And if we examine the possible choices available, as long as params stay immutable-by-default, we need a contrary modifier. This shows it would also be nicely consistent with this PR.

@XaviDCR92
Copy link
Author

however with our current syntax we cannot do what is shown. And if we examine the possible choices available, as long as params stay immutable-by-default, we need a contrary modifier.

@mikdusan That's for sure, but I encourage you to write a separate proposal for this instead. Otherwise, this proposal might become too big or cumbersome to be accepted and nor mine and your proposals would be finally accepted.

@Vexu Vexu added the proposal This issue suggests modifications. If it also has the "accepted" label then it is planned. label Apr 16, 2020
@Vexu Vexu added this to the 0.7.0 milestone Apr 16, 2020
@andrewrk
Copy link
Member

This was one of the things I considered early on, and landed confidently on status quo.

Use *var T for pointers to mutable data and []var T for arrays to mutable data.

Not planned. Status quo of *T vs *const T and []T vs []const T will remain.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
proposal This issue suggests modifications. If it also has the "accepted" label then it is planned.
Projects
None yet
Development

No branches or pull requests

7 participants