Skip to content

ability to create primitive types from TypeInfo, but not necessarily aggregate types #2907

Closed

Description

@andrewrk

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:

  • Void
  • Bool
  • NoReturn
  • Int (this would replace @IntType)
  • Float
  • Pointer
  • Array
  • ComptimeFloat
  • ComptimeInt
  • Undefined
  • Null
  • Optional
  • ErrorUnion
  • ErrorSet
  • Opaque (this would replace @OpaqueType)
  • Promise
  • Vector (this would replace @Vector)

This issue is a prerequisite to #383.

Activity

  1. added
    proposalThis issue suggests language modifications. If it also has the "accepted" label then it is planned.
    on Jul 16, 2019
  2. added this to the 0.5.0 milestone on Jul 16, 2019
  3. Sahnvour commented on Jul 16, 2019

    @Sahnvour
    Contributor

    In this proposal, if you try to make a struct, you get a compile error "unable to create struct type"

    Could this be conveyed by another name that @Type, like @BuiltinType but more well-thought ?

  4. marler8997 commented on Jul 16, 2019

    @marler8997
    Contributor

    Bikeshedding Disclaimer

    @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.

  5. thejoshwolfe commented on Jul 17, 2019

    @thejoshwolfe
    SponsorContributor

    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" 🤷‍♂️ .

  6. marler8997 commented on Aug 22, 2019

    @marler8997
    Contributor

    Should the @Type builtin only accept TypeInfo or should it also accept any instance of a TypeInfo sub-type? i.e. should this work?

    const MyPointerType = @Type(builtin.TypeInfo.Pointer {
        .size = builtin.TypeInfo.Pointer.Size.One,
        .is_const = false,
        .is_volatile = false,
        .alignment = 1,
        .child = u8,
        .is_allowzero = false,
    });

    Or should we require this?

    const MyPointerType = @Type(builtin.TypeInfo {
        .Pointer = builtin.TypeInfo.Pointer {
            .size = builtin.TypeInfo.Pointer.Size.One,
            .is_const = false,
            .is_volatile = false,
            .alignment = 1,
            .child = u8,
            .is_allowzero = false,
        }
    );

    Note that it shouldn't be much more code to implement.

  7. marler8997 commented on Aug 23, 2019

    @marler8997
    Contributor

    Implementation here: #3111

  8. andrewrk commented on Sep 4, 2019

    @andrewrk
    MemberAuthor

    This is mostly done thanks to @marler8997. The types left to implement are:

    • Array
    • Optional
    • ErrorUnion
    • ErrorSet
    • Enum
    • Opaque
    • FnFrame
    • AnyFrame
    • Vector
    • EnumLiteral
  9. modified the milestones: 0.5.0, 0.6.0 on Sep 4, 2019
  10. modified the milestones: 0.6.0, 0.7.0 on Feb 10, 2020
  11. tadeokondrak commented on Apr 28, 2020

    @tadeokondrak
  12. SpexGuy commented on May 5, 2020

    @SpexGuy
    Contributor

    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.

  13. tadeokondrak commented on May 11, 2020

    @tadeokondrak
    Contributor

    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

    fn SomeType() type {
        return if (comptime function())
            struct { const A = 1; const B = 2; }
        else
            struct { const A = 2; };
    }
  14. alexnask commented on May 11, 2020

    @alexnask
    Contributor

    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.

  15. tadeokondrak commented on Aug 27, 2020

    @tadeokondrak
    Contributor

    This is fully implemented now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    acceptedThis proposal is planned.proposalThis issue suggests language modifications. If it also has the "accepted" label then it is planned.

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions