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

Proposal: make comptime fields immutable (for realsies) #19483

Open
mlugg opened this issue Mar 29, 2024 · 4 comments
Open

Proposal: make comptime fields immutable (for realsies) #19483

mlugg opened this issue Mar 29, 2024 · 4 comments
Labels
frontend Tokenization, parsing, AstGen, Sema, and Liveness. proposal This issue suggests modifications. If it also has the "accepted" label then it is planned.
Milestone

Comments

@mlugg
Copy link
Member

mlugg commented Mar 29, 2024

Tuples and structs in Zig support comptime fields, which are effectively declarations with a fancy hat on. These fields have a fixed value which is associated with the type itself.

A slightly weird thing about comptime fields is that they're actually semantically considered mutable: the catch is that the value you store to them must be comptime-known to match the current value. For instance:

const S = struct {
    comptime a: [2]u32 = .{ 123, 456 },
};
test "store to comptime field" {
    var s: S = .{};
    s.a[0] = 123; // this is fine
    s.a = .{ 123, 456 }; // this is fine
    s.a[0] = 600; // this emits an error
}
foo.zig:8:12: error: value stored in comptime field does not match the default value of the field
    s.a[0] = 600; // this emits an error
    ~~~~~~~^~~~~

Because pointers to comptime fields are semantically considered mutable, they unfortunately have the same restrictions as pointers to comptime vars, introduced in #19414. This limits the usefulness of these fields, and can be particularly frustrating since fields of untyped anonymous initializations are implicitly made comptime.

However, there does not appear to be any reason these fields have to be mutable. I would guess that the main reason is for RLS-style initialization: in the example above, perhaps we want s = .{ .a = .{ 123, 456 } } to be valid. I think this makes sense, because of the fact that if no type were given, you would get a type with a comptime field; it would be strange if explicit specification of the struct removed the ability to initialize its comptime field. Thus, I do not propose disallowing comptime fields from appearing in struct iniitalization expressions, although the field initializer must -- like today -- be comptime-known and match the field value. I do, however, propose that "normal" pointers to such fields should always be considered immutable. They should have a const pointer type, and attempting to mutate through them at comptime should raise a compile error. This would remove the restrictions in place on these fields, allowing them to be referenced at runtime just like non-comptime fields. I believe this change would improve "perceived simplicity" of the language, i.e. how difficult it is to learn/understand (and the impact on actual spec simplicity should be fairly neural).

@mlugg mlugg added proposal This issue suggests modifications. If it also has the "accepted" label then it is planned. frontend Tokenization, parsing, AstGen, Sema, and Liveness. labels Mar 29, 2024
@mlugg mlugg added this to the 0.13.0 milestone Mar 29, 2024
@Lking03x
Copy link

Lking03x commented Apr 2, 2024

You are right the language should not accept that but it's not for RLS to work.

Zig struct "field" themselves have NO reason to be const/comptime AFAIK. For the use of static member declarations associated/namespaced with a struct type one do this:

const S = struct {
    // "const" or "var" as a normal variable declaration
    const a = expr;
    var b = expr2;
};

Both a and b are associated as static members, have a type which can be inferred, and their expression can be comptime.
a is immutable, b is not.

@silversquirl
Copy link
Contributor

@Lking03x comptime fields are an important and useful feature. Decls do not cover their usecases.

For example, they allow writer.print("{} {}\n", .{runtime_value, 7}) to inline the 7 because it's comptime-known, while still allowing runtime_value to be handled at runtime.

@ethernetsellout
Copy link

Would this entail rejecting #5675?

@mlugg
Copy link
Member Author

mlugg commented Apr 5, 2024

#5675 is a proposal which offers a completely different form of "comptime field" that exists today. This proposal, on the other hand, is a simple augmentation of the current feature.

Thus, acceptance and implementation of this proposal need not directly lead to rejection of #5675; it could still be accepted in future and overrule this behavior. (I should, however, note that I am like 95% confident that proposal will be rejected.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
frontend Tokenization, parsing, AstGen, Sema, and Liveness. 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

4 participants