From f481a91af6fbd15a61b828f49094a70a43183b4d Mon Sep 17 00:00:00 2001 From: Vyacheslav Egorov Date: Mon, 9 Aug 2021 16:46:17 +0300 Subject: [PATCH] Resolved review comments * improved motivation for the feature and noted additional languages with this feature * fixed terminology between 'argument' and 'parameter' * brought back support for default type pack parameter values * removed alternative syntax and described the decision between ':' and '=' in the design section * fixed drawback text and provided an example --- ...ntax-default-type-alias-type-parameters.md | 41 +++++++++++++------ 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/rfcs/syntax-default-type-alias-type-parameters.md b/rfcs/syntax-default-type-alias-type-parameters.md index 617eb084..77d1c024 100644 --- a/rfcs/syntax-default-type-alias-type-parameters.md +++ b/rfcs/syntax-default-type-alias-type-parameters.md @@ -7,7 +7,7 @@ Introduce syntax to provide default type values inside the type alias type param ## Motivation Luau has support for type parameters for type aliases and functions. -In languages with similar features like C++ and TypeScript, it is possible to specify default values and users with experience in those languages would like to use that in Luau. +In languages with similar features like C++, Rust, Flow and TypeScript, it is possible to specify default values for looser coupling and easier composability, and users with experience in those languages would like to have these design capabilities in Luau. Here is an example that is coming up frequently during development of GraphQL Luau library: ```lua @@ -18,9 +18,9 @@ export type GraphQLFieldResolver< > = (TSource, TArgs, TContext, GraphQLResolveInfo) -> any ``` If we could specify defaults like that, we won't have to write long type names when type alias is used unless specific customization is required. -Some engineers already skip these extra arguments and use `any` to save time, which gives worse typechecking quality. +Some engineers already skip these extra arguments and use `'any'` to save time, which gives worse typechecking quality. -Without default arguments it's also harder to refactor the code as each type alias reference that uses 'common' type arguments has to be updated. +Without default parameter values it's also harder to refactor the code as each type alias reference that uses 'common' type arguments has to be updated. While previous example uses a concrete type for default type value, it should also be possible to reference generic types from the same list: ```lua @@ -30,29 +30,35 @@ local a: Eq = ... local b: Eq = ... ``` -Generic functions in Luau also have a type parameter list, but it's not possible to specify type arguments at the call site and because of that, default type argument values for generic functions are not proposed. +Generic functions in Luau also have a type parameter list, but it's not possible to specify type arguments at the call site and because of that, default type parameter values for generic functions are not proposed. ## Design -If a default type argument value is assigned, following type parameters (on the right) must also have default type argument values. +If a default type parameter value is assigned, following type parameters (on the right) must also have default type parameter values. ```lua type A = ... -- not allowed ``` -Default type argument values can reference type parameters which were defined earlier (to the left): +Default type parameter values can reference type parameters which were defined earlier (to the left): ```lua type A = ...-- ok type A = ... -- not allowed ``` -Default type arguments are not allowed for type pack parameters. +Default type parameter values are also allowed for type packs: +```lua +type A -- ok, variadic type pack +type B -- ok, type pack with two elements +type C -- ok, type pack with one element +type D -- ok +``` --- -Syntax for type alias type argument is extended as follows: +Syntax for type alias type parameter is extended as follows: -```typearg ::= Name [`=' typeannotation]``` +```typeparameter ::= Name [`...'] [`=' typeannotation]``` Instead of storing a simple array of names in AstStatTypeAlias, we will store an array of structs containing the name and an optional default type value. @@ -68,11 +74,20 @@ local b: All<> -- not allowed If type is exported from a module, default type parameter values will still be available when module is imported. +--- +Type annotations in Luau are placed after `':'`, but we use `'='` here to assign a type value, not to imply that the type parameter on the left has a certain type. + +Type annotation with `':'` could be used in the future for bounded quantification which is orthogonal to the default type value. + ## Drawbacks -Previously, it was possible to reference type alias without type arguments inside that alias (recursive types). -We disallow that now, but if we decide to return that, there will be an ambiguity if all type parameters have a default value. +Other languages might allow references to the type alias without arguments inside the scope of that type alias to resolve into a recursive reference to the type alias with the same arguments. -## Alternatives +While that is not allowed in Luau right now, if we decide to change that in the future, we will have an ambiguity when all type alias parameters have default values: +```lua +-- ok if we allow Type to mean Type +type Type = { x: number, b: Type? } -We could use `:` instead of `=` to define default type parameter values. +-- ambiguity, Type could mean Type or Type +type Type = { x: number, b: Type? } +```