Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(92)

Side by Side Diff: docs/language/informal/generic-function-type-alias.md

Issue 2841483003: Added informal generic method syntax and generic function type specs. (Closed)
Patch Set: Review response Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 # Feature: Generic Function Type Alias
2
3 **Status**: Under implementation.
floitsch 2017/06/01 09:28:02 Implemented.
eernst 2017/07/06 10:02:13 Done.
4
5 **This document** is an informal specification of a feature supporting the
6 definition of function type aliases using a more expressive syntax than the
7 one available today, such that it also covers generic function types. The
8 feature also introduces syntax for specifying function types directly, such
9 that they can be used in type annotations etc. without going via a
10 `typedef`. This feature is being introduced into Dart starting Q4, 2016.
11
12 **This feature** introduces a new syntactic form of typedef declaration
13 which includes an identifier and a type, connecting the two with an equals
14 sign, `=`. The effect of such a declaration is that the name is declared to
15 be an alias for the type. Type parameterization may occur in the
16 declaration itself, as well as in the declared type. This feature also
17 introduces syntax for specifying function types directly, using a syntax
18 which is similar to the header of a function declaration.
19
20 The **motivation** for adding this feature is that it allows developers to
21 specify generic function types everywhere a type is expected, including
22 type annotations, return types, actual type arguments, and formal type
23 parameter bounds. Currently there is no way to specify a generic function
24 type in these situations. Even in the case where a generic function type
25 *can* be specified (such as a type annotation for a formal parameter) it
26 may be useful for readability to declare a name as an alias of a complex
27 type, and use that name instead of the type.
28
29 ## Examples
30
31 Using the new syntax, a function type alias may be declared as follows:
32
33 ```dart
34 typedef F = List<T> Function<T>(T);
35 ```
36
37 This declares `F` to be the type of a function that accepts one type
38 parameter `T` and one value parameter of type `T` whose name is
39 unspecified, and returns a result of type `List<T>`. It is possible to use
40 the new syntax to declare function types that we can already declare using
41 the existing typedef declaration. For instance, `G` and `H` both declare
42 the same type:
43
44 ```dart
45 typedef G = List<int> Function(int); // New form.
46 typedef List<int> H(int i); // Old form.
47 ```
48
49 Note that the name of the parameter is required in the old form, but the
50 type may be omitted. In contrast, the type is required in the new form, but
51 the name may be omitted.
52
53 The reason for having two ways to express the same thing is that the new
54 form seamlessly covers non-generic functions as well as generic ones, and
55 developers might prefer to use the new form everywhere, for improved
56 readability.
57
58 *We may deprecate the old form after a while, or we may choose
59 to keep it, because it is more concise. We may even change the old form to
60 allow omitting the name and not the type when only one identifier is
61 specified, if this is not too much of a breaking change. As an intermediate
62 step we could change the old form to always require both the type and the
63 name, such that no type expressions will silently change meaning.*
64
65 There is a difference between declaring a generic function type and
66 declaring a typedef which takes a type argument. The former is a
67 declaration of a single type which describes a certain class of runtime
68 entities: Functions that are capable of accepting some type arguments as
69 well as some value arguments, both at runtime. The latter is a type-level
70 function: It accepts a type argument at compile time and returns a type,
71 which may be used, say, as a type annotation. Dart has had support for
72 parameterized typedefs for a while, and the new syntax supports
73 parameterized typedefs as well. Here is an example of a parameterized
74 typedef, and a usage thereof:
75
76 ```dart
77 typedef I<T> = List<T> Function(T); // New form.
78 typedef List<T> J<T>(T t); // Old form.
79 I<int> myFunction(J<int> f) => f;
80 ```
81
82 Here, we have declared two equivalent parameterized typedefs `I` and `J`,
83 and we have used an instantiation of each of them in the type annotations
84 on `myFunction`. Note that the type of `myFunction` does not include *any*
85 generic types, it is just a function that accepts an argument and returns a
86 result, both of which have a non-generic function type that we have
87 obtained by instantiating a parameterized typedef. The argument type might
88 as well have been declared using the traditional function signature syntax,
89 and the return type (and the argument type, by the way) might as well have
90 been declared using a regular, non-parameterized typedef:
91
92 ```dart
93 typedef List<int> K(int i); // Old form, non-generic.
94 K myFunction2(List<int> f(int i)) => f; // Same as myFunction.
95 ```
96
97 The new syntax allows for using the two kinds of type parameters together:
98
99 ```dart
100 typedef L<T> = List<T> Function<S>(S, {T Function(int, S) factory});
101 ```
102
103 This declares `L` to be a parameterized typedef; when instantiating `L`
104 with an actual type argument as in `L<String>`, it becomes the type of a
105 generic function that accepts a type argument `S` and two value arguments:
106 one required positional argument of type `S`, and one named optional
107 argument with name `factory` and type `String Function(int, S)`; finally,
108 it returns a value of type `List<String>`.
109
110 ## Syntax
111
112 The new form of `typedef` declaration uses the following syntax (there are
113 no deletions from the grammar; addition of a new rule or a new alternative
114 in a rule is marked with NEW and modified rules are marked CHANGED):
115
116 ```
117 typeAlias:
118 metadata 'typedef' typeAliasBody |
119 metadata 'typedef' identifier typeParameters? '=' functionType ';' // NEW
120 functionType: // NEW
121 returnType? 'Function' typeParameters? parameterTypeList
122 parameterTypeList: // NEW
123 '(' ')' |
124 '(' normalParameterTypes ','? ')' |
125 '(' normalParameterTypes ',' optionalParameterTypes ')' |
126 '(' optionalParameterTypes ')'
127 normalParameterTypes: // NEW
128 normalParameterType (',' normalParameterType)*
129 normalParameterType: // NEW
130 type | typedIdentifier
131 optionalParameterTypes: // NEW
132 optionalPositionalParameterTypes | namedParameterTypes
133 optionalPositionalParameterTypes: // NEW
134 '[' normalParameterTypes ','? ']'
135 namedParameterTypes: // NEW
136 '{' typedIdentifier (',' typedIdentifier)* ','? '}'
137 typedIdentifier: // NEW
138 type identifier
139 type: // CHANGED
140 typeWithoutFunction |
141 functionType
142 typeWithoutFunction: // NEW
143 typeName typeArguments?
144 typeWithoutFunctionList: // NEW
145 typeWithoutFunction (',' typeWithoutFunction)*
146 mixins: // CHANGED
147 'with' typeWithoutFunctionList
148 interfaces: // CHANGED
149 'implements' typeWithoutFunctionList
150 superclass: // CHANGED
151 'extends' typeWithoutFunction
152 mixinApplication: // CHANGED
153 typeWithoutFunction mixins interfaces?
154 newExpression: // CHANGED
155 'new' typeWithoutFunction ('.' identifier)? arguments
156 constObjectExpression: // CHANGED
157 'const' typeWithoutFunction ('.' identifier)? arguments
158 redirectingFactoryConstructorSignature: // CHANGED
159 'const'? 'factory' identifier ('.' identifier)?
160 formalParameterList '=' typeWithoutFunction ('.' identifier)?
161 ```
162
163 The syntax relies on treating `Function` as a fixed element in a function
164 type, similar to a keyword or a symbol (many languages use symbols like
165 `->` to mark function types).
166
167 *The rationale for using this form is that it makes a function type very
168 similar to the header in a declaration of a function with that type: Just
169 replace `Function` by the name of the function, and add missing parameter
170 names and default values.*
171
172 *The syntax differs from the existing function type syntax
173 (`functionSignature`) in that the existing syntax allows the type of a
174 parameter to be omitted, but the new syntax allows parameter names to be
175 omitted. The rationale for this change is that a function type where a
176 parameter has a specified name and no type is very likely to be a
177 mistake. For instance, `int Function(int)` should not be the type of a
178 function that accepts an argument named "int" of type `dynamic`, it should
179 specify `int` as the parameter type and allow the name to be
180 unspecified. It is still possible to opt in and specify the parameter name,
181 which may be useful as documentation, e.g., if several arguments have the
182 same type.*
183
184 The modification of the rule for the nonterminal `type` may cause parsing
185 ambiguities. We intend to handle them by the following disambiguation rule
186 in the parser: If the parser is at a location L where the tokens starting
187 at L may be a `type` or some other construct (e.g., in the body of a
188 method, when parsing something that may be a statement and may also be a
189 declaration), the parser can commit to parsing a type by detecting that it
190 is looking at the identifier `Function` followed by `<` or `(`, or that it
191 is looking at a type followed by the identifier `Function` followed by `<`
192 or `(`.
193
194 *Note that this disambiguation rule does require parsers to have unlimited
195 lookahead. However, if a "diet parsing" strategy is used where the token
196 stream already contains references from each opening bracket (such as `<`
197 or `(`) to the corresponding closing bracket then the decision can be
198 taken in a fixed number of steps: If the current token is `Function` then
199 check the immediate successor (`<` or `(` means yes, we are looking at
200 a `type`, everything else means no) and we're done; if the first token is
201 an `identifier` other than `Function` then we can check whether it is a
202 `qualified` by looking at no more than the two next tokens, and we may then
203 check whether the next token again is `<`; if it is not then we look for
204 `Function` and the token after that, and if it is `<` then look for the
205 corresponding `>` (we have now skipped a generic class type), and then
206 the successor to that token again must be `Function`, and we finally check
207 its successor (looking for `<` or `(` again). This skips over the
208 presumed type arguments to a generic class type without checking that they
209 are actually type arguments, but we conjecture that there are no
210 syntactically correct alternatives (for example, we conjecture that there
211 is no syntactically correct statement, not a declaration, starting with
212 `SomeIdentifier<...> Function(...` where the angle brackets are balanced).*
213
214 *Note that this disambiguation rule will prevent parsing some otherwise
215 correct programs. For instance, the declaration of an asynchronous function
216 named `Function` with an omitted return type (meaning `dynamic`) and an
217 argument named `int` of type `dynamic` using `Function(int) async {}` will
218 be a parse error, because the parser will commit to parsing a type after
219 having seen "`Function(`" as a lookahead. However, we do not expect that it
220 will be a serious problem for developers to be unable to write such
221 programs.*
222
223 ## Scoping
224
225 Consider a typedef declaration as introduced by this feature, i.e., a
226 construct on the form
227
228 ```
229 metadata 'typedef' identifier typeParameters? '=' functionType ';'
230 ```
231
232 This declaration introduces `identifier` into the enclosing library scope.
233
234 Consider a parameterized typedef, i.e., a construct on the form
235
236 ```
237 metadata 'typedef' identifier typeParameters '=' functionType ';'
238 ```
239
240 Note that in this case the `typeParameters` are present, not optional. This
241 construct introduces a scope known as the *typedef scope*. Each typedef
242 scope is nested inside the library scope of the enclosing library. Every
243 formal type parameter declared by the `typeParameters` in this construct
244 introduces a type variable into its enclosing typedef scope. The typedef
245 scope is the current scope for the `typeParameters` themselves, and for the
246 `functionType`.
247
248 Consider a `functionType` specifying a generic function type, i.e., a
249 construct on the form
250
251 ```
252 returnType? 'Function' typeParameters parameterTypeList
253 ```
254
255 Note again that `typeParameters` are present, not optional. This construct
256 introduces a scope known as a *function type scope*. The function type
257 scope is nested inside the current scope for the associated `functionType`.
258 Every formal type parameter declared by the `typeParameters` introduces a
259 type variable into its enclosing function type scope. The function type
260 scope is the current scope for the entire `functionType`.
261
262 *This implies that parameterized typedefs and function types are capable of
263 specifying F-bounded type parameters, because the type parameters are in
264 scope in the type parameter list itself.*
265
266 ## Static Analysis
267
268 Consider a typedef declaration as introduced by this feature, i.e., a
269 construct on the form
270
271 ```
272 metadata 'typedef' identifier typeParameters? '=' functionType ';'
273 ```
274
275 It is a compile-time error if a name *N* introduced into a library scope by
276 a typedef has an associated `functionType` which depends directly or
277 indirectly on *N*. It is a compile-time error if a bound on a formal type
278 parameter in `typeParameters` is not a type. It is a compile-time error if
279 a typedef has an associated `functionType` which is not a type when
280 analyzed under the assumption that every identifier resolving to a formal
281 type parameter in `typeParameters` is a type. It is a compile-time error if
282 an instantiation *F<T1..Tk>* of a parameterized typedef is mal-bounded.
283
284 *This implies that a typedef cannot be recursive. It can only introduce a
285 name as an alias for a type which is already expressible as a
286 `functionType`, or a name for a type-level function F where every
287 well-bounded invocation `F<T1..Tk>` denotes a type which could be expressed
288 as a `functionType`. Following
289 [common terminology](https://en.wikipedia.org/wiki/Kind_(type_theory)), we
290 could say that a typedef can define entities of kind ` * ` and of kind
291 ` * -> * `, and, when it is assumed that every formal type parameter of the
292 typedef (if any) has kind ` * `, it is an error if the right hand side of the
293 declaration denotes an entity of any other kind than ` * `; in particular,
294 declarations of entities of kind ` * -> * ` cannot be curried.*
295
296 It is a compile-time error if a name declared in a typedef, with or without
297 actual type arguments, is used as a superclass, superinterface, or mixin.
298
299 ## Dynamic Semantics
300
301 The addition of this feature does not change the dynamic semantics of
302 Dart.
303
304 ## Changes
305
306 2017-Jan-04: Adjusted the grammar to require named parameter types to have
307 a type (previously, the type was optional).
308
309 2016-Dec-21: Changed the grammar to prevent the new function type syntax
310 in several locations (for instance, as a super class or as a mixin). The
311 main change in the grammar is the introduction of `typeWithoutFunction`.
312
313 2016-Dec-15: Changed the grammar to prevent the old style function types
314 (derived from `functionSignature` in the grammar) from occurring inside
315 the new style (`functionType`).
OLDNEW
« no previous file with comments | « no previous file | docs/language/informal/generic-method-syntax.md » ('j') | docs/language/informal/generic-method-syntax.md » ('J')

Powered by Google App Engine
This is Rietveld 408576698