You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
ability to create primitive types from TypeInfo, but not necessarily aggregate types #2907
We have the @reify proposal here: #383. One of the reasons it's not accepted yet is that it's big and scary and has some pretty serious implications for how complicated zig code is allowed to be.
This is a proposal which is a subset of #383 with a smaller scope, which is a builtin function (and I'm going to suggest a different name here) @Type which turns builtin.TypeInfo into a type. In this proposal, if you try to make a struct, you get a compile error "unable to create struct type". The list of supported types would be:
@InfoType could work as it's the reverse of @typeInfo and it's the functional inverse of it. Of course @Type is nice and short so I would only suggest a longer name if there were potential name conflicts with @Type.
We can categorize types by whether their type info contains a bounded amount of information, and whether they refer to another type. An error set's type info contains a slice of possible errors, so that's an unbounded amount of information. An optional type contains another type, so that's a recursive type.
The list of types is taken from the docs on @typeInfo
Type
Unbounded
Recursive
Type
Void
Bool
NoReturn
Int
Float
Pointer
✔️
Array
✔️
Struct
✔️
✔️
ComptimeFloat
ComptimeInt
Undefined
Null
Optional
✔️
ErrorUnion
✔️
ErrorSet
✔️
Enum[1]
✔️
Union[2]
✔️
✔️
Fn
✔️
✔️
BoundFn
✔️
✔️
ArgTuple[3]
✔️
✔️
Opaque
Promise
✔️
Vector
✔️
EnumLiteral[4]
[1] I'm not counting the decls here. I'm not even sure why enum's are allowed to have decls. And maybe all decls should be moved out of TypeInfo, since they're not relevant to any instance of the type. The rest of this discussion will assume that TypeInfo does not include decls.
[2] The in-memory space used by a union is bounded, but the type info is effectively the same as a struct's type info.
[3] I'm pretty sure ArgTuple should have []type instead of void type info.
[4] EnumLiteral might store the identifier characters, which is kinda unbounded,
but that doesn't seem significant to this discussion.
This proposal seems to be attempting to exclude the ✔️ ✔️ cases, which means we're missing Type, Enum, and EnumLiteral.
The term "primitive type" to me means types that are bounded and non-recursive. This includes the types you can express with a single keyword in zig (void, u32, comptime_float, noreturn, etc.). There are also some singleton types whose value is a keyword and whose type can be expressed with @typeOf() (undefined, null).
My definition of primitive types also includes Opaque types, which are quite the special case. The OP comment "(this would replace @OpaqueType)" suggests that @Type(.Opaque) is how you would create an opaque type, making opaque types an exception to @Type(@typeInfo(T)) == T. This seems a little strange.
I think there's a good argument to be able to construct pointer types with some builtin function, because pointer types have so much metadata (const, align(N), etc.). While there is not a good reason to support creating optional types (since you could just ?@Type(T),), it makes more sense if we already want to do pointer types. Then we should do all the bounded recursive types, like Array, Vector, Promise. But I think we should call it something other than "primitive types". I don't have a good name for it right now other than "bounded, possibly-recursive types" 🤷♂️ .
Reacted by Eira Fransham, Komu Wairagu, Sahnvour, bb010g and Alexandre HOUNDJAGO
I'm not certain that we should allow @Type to construct enums. Constructing anything that declares an identifier from a comptime string would make "go to definition" and autocomplete features of an editor extremely difficult to implement (would have to embed an entire comptime VM that works on half-written code), and would mean it's impossible to know you'll be able to grep for the definition of an enum literal (or, soon after, struct field). If you need to write an api that dynamically creates comptime-known values with names that are comptime-known strings, it can be done by exposing a function fn getValue(comptime name: []const u8) GenType, or with code generation. So this rule doesn't limit comptime functionality.
Constructing anything that declares an identifier from a comptime string would make "go to definition" and autocomplete features of an editor extremely difficult to implement (would have to embed an entire comptime VM that works on half-written code)
I think this is already true, you can do something like
I agree, you basically need to be a zig compiler (or at least comptime engine) to correctly do completions etc, adding aggregate type reification does make it slightly more diffciult but not by a huge degreee.
Personally I would be okay with generating any aggregate type as long as you cannot generate functions in its namespace but I do get the arguments against it.
Having enum reification alone will aready let metaprogramming code do a lot more without introducing really surprising behavior.
Activity
Sahnvour commentedon Jul 16, 2019
Could this be conveyed by another name that
@Type, like@BuiltinTypebut more well-thought ?marler8997 commentedon Jul 16, 2019
Bikeshedding Disclaimer
@InfoTypecould work as it's the reverse of@typeInfoand it's the functional inverse of it. Of course@Typeis nice and short so I would only suggest a longer name if there were potential name conflicts with@Type.thejoshwolfe commentedon Jul 17, 2019
We can categorize types by whether their type info contains a bounded amount of information, and whether they refer to another type. An error set's type info contains a slice of possible errors, so that's an unbounded amount of information. An optional type contains another type, so that's a recursive type.
The list of types is taken from the docs on
@typeInfo[1] I'm not counting the
declshere. I'm not even sure why enum's are allowed to have decls. And maybe all decls should be moved out ofTypeInfo, since they're not relevant to any instance of the type. The rest of this discussion will assume thatTypeInfodoes not include decls.[2] The in-memory space used by a union is bounded, but the type info is effectively the same as a struct's type info.
[3] I'm pretty sure ArgTuple should have
[]typeinstead ofvoidtype info.[4] EnumLiteral might store the identifier characters, which is kinda unbounded,
but that doesn't seem significant to this discussion.
This proposal seems to be attempting to exclude the ✔️ ✔️ cases, which means we're missing Type, Enum, and EnumLiteral.
The term "primitive type" to me means types that are bounded and non-recursive. This includes the types you can express with a single keyword in zig (
void,u32,comptime_float,noreturn, etc.). There are also some singleton types whose value is a keyword and whose type can be expressed with@typeOf()(undefined,null).My definition of primitive types also includes Opaque types, which are quite the special case. The OP comment "(this would replace
@OpaqueType)" suggests that@Type(.Opaque)is how you would create an opaque type, making opaque types an exception to@Type(@typeInfo(T)) == T. This seems a little strange.I think there's a good argument to be able to construct pointer types with some builtin function, because pointer types have so much metadata (
const,align(N), etc.). While there is not a good reason to support creating optional types (since you could just?@Type(T),), it makes more sense if we already want to do pointer types. Then we should do all the bounded recursive types, like Array, Vector, Promise. But I think we should call it something other than "primitive types". I don't have a good name for it right now other than "bounded, possibly-recursive types" 🤷♂️ .marler8997 commentedon Aug 22, 2019
Should the
@Typebuiltin only acceptTypeInfoor should it also accept any instance of aTypeInfosub-type? i.e. should this work?Or should we require this?
Note that it shouldn't be much more code to implement.
marler8997 commentedon Aug 23, 2019
Implementation here: #3111
andrewrk commentedon Sep 4, 2019
This is mostly done thanks to @marler8997. The types left to implement are:
tadeokondrak commentedon Apr 28, 2020
SpexGuy commentedon May 5, 2020
I'm not certain that we should allow
@Typeto construct enums. Constructing anything that declares an identifier from a comptime string would make "go to definition" and autocomplete features of an editor extremely difficult to implement (would have to embed an entire comptime VM that works on half-written code), and would mean it's impossible to know you'll be able to grep for the definition of an enum literal (or, soon after, struct field). If you need to write an api that dynamically creates comptime-known values with names that are comptime-known strings, it can be done by exposing a functionfn getValue(comptime name: []const u8) GenType, or with code generation. So this rule doesn't limit comptime functionality.tadeokondrak commentedon May 11, 2020
I think this is already true, you can do something like
alexnask commentedon May 11, 2020
I agree, you basically need to be a zig compiler (or at least comptime engine) to correctly do completions etc, adding aggregate type reification does make it slightly more diffciult but not by a huge degreee.
Personally I would be okay with generating any aggregate type as long as you cannot generate functions in its namespace but I do get the arguments against it.
Having enum reification alone will aready let metaprogramming code do a lot more without introducing really surprising behavior.
tadeokondrak commentedon Aug 27, 2020
This is fully implemented now.