Open ghost opened 4 years ago
This indeed looks clean, and I think I even tried this as a first attempt to basically have instance bases comptime variables, rather than global ones.
This seems very intuitive and simple to understand to me :)
I'm in agreement on this one. This accomplishes a similar feat to the closure-over-comptime-var trick, but is much easier to read and work with. I'm a bit worried about this leading to potential code bloat or compile time bloat, since the type is effectively generic and every call using it ends up generating a new function. But tuples and closure-over-comptime-var have a similar problem, and people seem to be ok with those, so maybe this is ok too.
Types with comptime fields would have some fundamental limitations, which are essentially the same limitations covering pointers comptime vars. The compiler has to be able to track the instance through its entire lifetime. You can't store it somewhere and retrieve it later, unless the storage location is also a comptime var. Like async, these limitations are viral. A struct containing a struct containing a comptime field inherits all of these limits.
Obviously such a struct cannot be
packed
orextern
.
Why not? The proposed comptime
fields would exist only at compile time, so they should not affect runtime memory layout in any way.
The crux of #5895 (#7396) is now accepted, so its individual ideas now make sense on their own. Welcome back!
Types with comptime fields would have some fundamental limitations, which are essentially the same limitations covering pointers comptime vars. The compiler has to be able to track the instance through its entire lifetime. You can't store it somewhere and retrieve it later, unless the storage location is also a comptime var. Like async, these limitations are viral. A struct containing a struct containing a comptime field inherits all of these limits.
What if the user or a struct method specifies the values of the comptime fields when dereferencing pointers to such structs?
Here's how this proposal could be implemented in my simple mind:
comptime
fields, and one of non-comptime
fields.comptime
fields and a comptime
-known pointer to the comptime
fields.
comptime
argument.)comptime var
-s, writing to comptime
fields (whether directly or through a pointer) at runtime / depending on runtime-branching is a compile error.I think equivalent behavior is already doable with @typeInfo
and @Type
in userspace,
but less readable because @Type
doesn't support reifying declarations,
and it requires manually splitting arguments and routing field accesses,
all of which add a lot of noise over the proposed language feature.
I'd like to point out a completely different usecase that this would also allow: comptime default function parameters.
A somewhat common pattern is to do something like this:
fn foo(args: FooArgs) void {}
const FooArgs = struct {
a: u32 = 1,
b: MyEnum = .bar,
c: u8 = ' ',
};
However, afaik there is no way to do this pattern for comptime arguments. I think this pattern may become ever more common with the addition of decl literals allowing quick shortcuts, and implementing this would allow comptime arguments to participate in this too.
However, afaik there is no way to do this pattern for comptime arguments.
@TheHonestHare The same is already possible if you separate comptime and runtime arguments into separate types:
fn foo(comptime c: FooComptimeArgs, r: FooRuntimeArgs) void {...}
test foo {foo(.{}, .{});}
Being able to unify both in a single argument can be helpful, though for more complex uses like generic arguments (dependent fields), reflection on an anytype
field is still the most versatile.
And if every callsite can provide its own type, then status-quo constant comptime
fields are often sufficient.
(DRAG IT, DROP IT, FOLD-UNFOLD IT)
5578 proposes, in my opinion, a very ugly solution to its problem. The same use case could be accomplished by accompanying each value with a comptime
giveToken
, but then there's the problem of encapsulating this functionality. This could be done very cleanly if structs were allowed to exist partly at comptime, partly at runtime, like so:Such fields would of course inherit most of the restrictions of comptime variables -- i.e. no setting in runtime control flow constructs, no setting to runtime values etc., although non-comptime fields would not have these restrictions. Methods would read and write comptime fields but otherwise run at runtime when appropriate. Obviously such a struct cannot be
packed
orextern
, for the same reason that functions with comptime parameters cannot have the C calling convention.