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

Side by Side Diff: docs/language/informal/generic-method-syntax.md

Issue 2841483003: Added informal generic method syntax and generic function type specs. (Closed)
Patch Set: Reformatted to fit in 80 columns, except one url Created 3 years, 8 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 Method Syntax
2
3 **This document** is an informal specification of the support for generic
4 methods and functions which has been implemented in `dart2js` with option
5 `--generic-method-syntax`, starting with commit
6 [acc5f59](https://github.com/dart-lang/sdk/commit/acc5f59a99d5d8747459c935e6360a c325606cc6).
7 In SDK 1.21 this feature is available by default (i.e., also without the
8 option) in the virtual machine and the analyzer, as well as in `dart2js`.
9
10 The **motivation for** having this **feature** is that it enables partial
11 support for generic methods and functions, thus providing a bridge between
12 not having generic methods and having full support for generic methods. In
13 particular, code declaring and using generic methods may be type checked and
14 compiled in strong mode, and the same code will now be acceptable in
15 standard (non-strong) mode as well. The semantics is different in certain
16 cases, but standard mode analysis will emit diagnostic messages (e.g.,
17 errors) for that.
18
19 In this document, the word **routine** will be used when referring to
20 something which can be a method, a top level function, a local function, or
21 a function literal expression.
22
23 With **this feature** it is possible to compile code where generic methods
24 and functions are declared, implemented, and invoked. The runtime semantics
25 does not include reification of type arguments. Evaluations of the runtime
26 value of a routine type parameter is a runtime error or yields `dynamic`,
27 depending on the context. No type checking takes place at usages of a method
28 or function type parameter in the body, and no type checking regarding
29 explicitly specified or omitted type arguments takes place at call sites.
30
31 In short, generic methods and functions are supported syntactically, and the
32 runtime semantics prevents dynamic usages of the type argument values, but
33 it allows all usages where that dynamic value is not required. For instance,
34 a generic routine type parameter, `T`, cannot be used in an expression like
35 `x is T`, but it can be used as a type annotation. In a context where other
36 tools may perform type checking, this allows for a similar level of
37 expressive power as do language designs where type arguments are erased at
38 compile time.
39
40 The **motivation for** this **document** is that it serves as an informal
41 specification for the implementation of support for the generic method
42 syntax feature in all Dart tools.
43
44 ## Syntax
45
46 The syntactic elements which are added or modified in order to support this
47 feature are as follows, based on grammar rules given in the Dart Language
48 Specification (Aug 19, 2015).
49
50 ```
51 formalParameterPart:
52 typeParameters? formalParameterList
53 functionSignature:
54 metadata returnType? identifier formalParameterPart
55 typeParameter:
56 metadata identifier (('extends'|'super') type)?
Lasse Reichstein Nielsen 2017/04/26 09:15:31 Remove `super`. We are not planning on adding it r
eernst 2017/05/19 18:49:36 Done.
57 functionExpression:
58 formalParameterPart functionBody
59 fieldFormalParameter:
60 metadata finalConstVarOrType? 'this' '.' identifier
61 formalParameterPart?
62 argumentPart:
63 typeArguments? arguments
64 selector:
65 assignableSelector | argumentPart
66 assignableExpression:
67 primary (argumentPart* assignableSelector)+ |
68 'super' unconditionalAssignableSelector |
69 identifier
70 cascadeSection:
71 '..' (cascadeSelector argumentPart*)
72 (assignableSelector argumentPart*)*
73 (assignmentOperator expressionWithoutCascade)?
74 ```
75
76 In a [draft specification](https://codereview.chromium.org/1177073002) of
77 generic methods from June 2015, the number of grammar changes is
78 significantly higher, but that form can be obtained via renaming.
79
80 This extension to the grammar gives rise to an **ambiguity** where the same
81 tokens may be angle brackets of a type argument list as well as relational
82 operators. For instance, `foo(a<b,c>(d))`[^1] may be parsed as a
83 `postfixExpression` on the form `primary arguments` where the arguments are
84 two relational expressions (`a<b` and `c>(d)`), and it may also be parsed
85 such that there is a single argument which is an invocation of a generic
86 function (`a<b,c>(d)`). The ambiguity is resolved in **favor** of the
87 **generic function invocation** whenever the `primary` is followed by a
88 balanced pair of angle brackets where the next token after the final `>` is
89 a left parenthesis (in short, we are "looking at `< .. >(`").
Lasse Reichstein Nielsen 2017/04/26 09:15:31 Drop the "whenever". *The ambiguity* is always res
eernst 2017/05/19 18:49:35 That was not the approach that I specified, I took
Lasse Reichstein Nielsen 2017/06/01 07:56:59 I understand the lure of the O(1) shortcut (given
90
91 This implies that an expression like `foo(a<b,2>(d))` will be rejected
Lasse Reichstein Nielsen 2017/04/26 09:15:31 What does "rejeceted" mean? In any case, remove en
eernst 2017/05/19 18:49:35 It is a syntax error.
Lasse Reichstein Nielsen 2017/06/01 07:57:00 I think it is possible - because the preferred int
92 because it is parsed such that `foo` gets one argument which must be a
93 generic function invocation, but `2` cannot parse correctly as a
94 `type`. This is a breaking change, because the same expression used to parse
95 correctly as an invocation of `foo` with two arguments.
96
97 The **reason** why the generic function invocation is favored over the
98 relational expressions is that it is considered to be a rare exception that
99 this ambiguity arises: It requires a balanced set of angle brackets followed
100 by a left parenthesis, which is already an unusual form. On top of that, the
101 style guide recommendation to use named parameters for boolean arguments
102 helps making this situation even less common.
103
104 If it does occur then there is an easy **workaround**: an extra set of
105 parentheses (as in `foo(a<b,(2>(d)))`) will resolve the ambiguity in the
106 direction of relational expressions; or we might simply be able to remove
107 the parentheses around the last expression (as in `foo(a<b,2>d)`), which
108 will also eliminate the ambiguity.
109
110 It should be noted that parsing techniques like recursive descent seem to
111 conflict with this approach to disambiguation: Determining whether the
112 remaining input starts with a balanced expression on the form `<` .. `>`
113 seems to imply a need for an unbounded lookahead. However, if some type of
114 "diet" parsing is used and various kinds of bracket tokens are matched up
115 during the lexical analysis then it takes only a simple O(1) check in the
116 parser to perform the required check.
Lasse Reichstein Nielsen 2017/04/26 09:15:31 Drop this section, or rewrite it to suggest, as an
eernst 2017/05/19 18:49:35 This should be commentary; changed the font to ita
117
118 ## Scope of the Mechanism
119
120 With the syntax in place, it is obvious that certain potential extensions
121 have **not** been **included**.
122
123 For instance, constructors, setters, getters, and operators cannot be
124 declared as generic. Actual type arguments cannot be passed at invocation
125 sites for setters, getters, and operators, and for constructors there is a
126 need to find a way to distinguish between type arguments for the new
127 instance and type arguments for the constructor itself. It is possible that
Lasse Reichstein Nielsen 2017/04/26 09:15:31 The second sentence seems to assume that construct
eernst 2017/05/19 18:49:36 The second sentence is intended to explain why con
Lasse Reichstein Nielsen 2017/06/01 07:56:59 The primary reason we will not have generic getter
128 some of these restrictions will be lifted in a full-fledged version of this
129 extension.
Lasse Reichstein Nielsen 2017/04/26 09:15:31 Not really, no. Setters and getters will not be g
eernst 2017/05/19 18:49:35 This is exactly like the spec when it says that th
130
131 Conversely, the inclusion of lower bounds for type parameters (using the
132 keyword `super`) serves to demonstrate that lower bounds fit well into the
133 syntax. There is no guarantee that a final version of generic methods will
134 support lower bounds, and it is not required that an implementation must
135 support them.
Lasse Reichstein Nielsen 2017/04/26 09:15:31 Drop mentions of lower bounds.
eernst 2017/05/19 18:49:36 Done.
136
137 In general, the support for generic methods offered by this feature is not
138 intended to be complete, it is **intended** to allow **for** **experiments**
139 such that a final version of the generic method support can be designed
140 well, **and** it is intended to allow for the **subset of usages** where
141 reification is not required.
Lasse Reichstein Nielsen 2017/04/26 09:15:31 This disagrees with the paragraph above saying tha
eernst 2017/05/19 18:49:36 Done. I inserted a shorted paragraph explaining t
142
143 ## Resolution and Type Checking
144
145 In order to be useful, the support for generic methods and functions must be
146 sufficiently complete and consistent to **avoid spurious** diagnostic
147 **messages**. In particular, even though no regular type checks take place
148 at usages of routine type parameters in the body where they are in scope,
149 those type parameters should be resolved. If they had been ignored then any
150 usage of a routine type parameter `X` would give rise to a `Cannot resolve
151 type X` error message, or the usage might resolve to other declarations of
152 `X` in enclosing scopes such as a class type parameter, both of which is
153 unacceptable.
154
155 In `dart2js` resolution, the desired behavior has been achieved by adding a
156 new type parameter **scope** and putting the type parameters into that
157 scope, giving each of them the bound `dynamic`. The type parameter scope is
158 the current scope during resolution of the routine signature and the type
159 parameter bounds, it encloses the formal parameter scope of the routine, and
160 the formal parameter scope in turn encloses the body scope.
161
162 This implies that every usage of a routine type parameter is treated during
163 **type checking** as if it had been an alias for the type `dynamic`.
164
165 Static checks for **invocations** of methods or functions where type
166 arguments are passed are omitted entirely: The type arguments are parsed,
167 but no checks are applied to certify that the given routine accepts type
168 arguments, and no checks are applied for bound violations. Similarly, no
169 checks are performed for invocations where no type arguments are passed,
170 whether or not the given routine is statically known to accept type
171 arguments.
172
173 Certain usages of a routine type parameter `X` give rise to **errors**: It
174 is a compile-time error if `X` is used as a type literal (e.g., `foo(X)`),
175 or in an expression on the form `e is X` or `e is! X`.
176
177 It could be argued that it should be a warning or an error if a routine type
178 parameter `X` is used in an expression on the form `e as X`. The blind
179 success of this test at runtime may introduce bugs into correct programs in
180 situations where the type constraint is violated; in particular, this could
181 cause "wrong" objects to propagate through local variables and parameters
182 and even into data structures (say, when a `List<T>` is actually a
183 `List<dynamic>`, because `T` is not present at runtime when the list is
184 created). However, considering that these type constraint violations are
185 expected to be rare, and considering that it is common to require that
186 programs compile without warnings, we have chosen to omit this warning. A
187 tool is still free to emit a hint, or in some other way indicate that there
188 is an issue.
189
190 ## Dynamic semantics
191
192 If a routine invocation specifies actual type arguments, e.g., `int` in the
193 **invocation** `f<int>(42)`, those type arguments will not be evaluated at
194 runtime, and they will not be passed to the routine in the
195 invocation. Similarly, no type arguments are ever passed to a generic
196 routine due to call-site inference. This corresponds to the fact that the
197 type arguments have no runtime representation.
198
199 When the body of a generic **routine** is **executed**, usages of the formal
200 type parameters will either result in a run-time error, or they will yield
201 the value yielded by an evaluation of `dynamic`, following the treatment of
Lasse Reichstein Nielsen 2017/04/26 09:15:31 if `dynamic` can be shadowed, this it's correct to
eernst 2017/05/19 18:49:35 Incorrect?
Lasse Reichstein Nielsen 2017/06/01 07:56:59 Yes "incorrect". Read what I mean :) I agree that
202 malformed types in Dart. There are the following cases:
203
204 When `X` is a routine type parameter, the evaluation of `e is X`, `e is! X`,
205 and `X` used as a type literal proceeds as if `X` had been a malformed type,
Lasse Reichstein Nielsen 2017/04/26 09:15:31 a type literal -> an expression I'm not sure exact
eernst 2017/05/19 18:49:36 Done.
206 producing a dynamic error if the type test itself is reached; the evaluation
207 of `e as X` has the same outcome as the evaluation of `e`.
208
209 Note that the forms containing `is` are compile-time errors, which means
210 that implementations are free to reject the program, or to compile the
211 program with a different runtime semantics for these expressions. The
Lasse Reichstein Nielsen 2017/04/26 09:15:31 If it's specified as a compile-time error, then co
eernst 2017/05/19 18:49:35 If we insist that the language specification must
Lasse Reichstein Nielsen 2017/06/01 07:56:59 I'm not saying that compilers can't choose to impl
212 rationale for `dart2js` to allow the construct and compile it to a run time
213 error is that (1) this allows more programs using generic methods to be
214 compiled, and (2) an `is` expression that blindly returns `true` every time
215 (or `false` every time) may silently introduce a bug into an otherwise
216 correct program, so the expression must fail if it is ever evaluated.
217
218 When `X` is a routine type parameter which is passed as a type argument to a
219 generic class instantiation `G` which is itself used in `e is G`, `e is! G`,
Lasse Reichstein Nielsen 2017/04/26 09:15:31 Isn't this just saying that in a generic class ins
eernst 2017/05/19 18:49:35 Right, this can be compressed. Did that.
220 `e as G`, and `G` used as a type literal, evaluation again proceeds as if
221 `X` were a malformed type, which in this case means that it is treated like
222 `dynamic`.
223
224 This may be surprising, so let us consider a couple of examples: When `X` is
225 a routine type parameter, `42 is X` raises a dynamic error, `<int>[42] is
226 List<X>` yields the value `true`, and `42 as X` yields `42`, no matter
227 whether the syntax for the invocation of the routine included an actual type
228 argument, and, if so, no matter which value the actual type argument would
229 have had at the invocation.
230
231 Object construction is similar: When `X` is a routine type parameter which
232 is a passed as a type argument to a constructor invocation, the value passed
233 to the constructor will be the value yielded by an evaluation of `dynamic`.
Lasse Reichstein Nielsen 2017/04/26 09:15:31 Drop "the value yielded by an evaluation of `dynam
eernst 2017/05/19 18:49:36 Adjusted the sentence in approximately that manner
234
235 In **checked mode**, when `X` is a routine type parameter which is used as a
236 type annotation or in a generic type `G` used as a type annotation, no
237 checked mode checks will ever fail for initialization or assignment to a
238 local variable or parameter whose type annotation is `X`, and if the type
239 annotation is a generic type `G` that contains `X`, checked mode checks will
240 succeed or fail as if `X` had been the type `dynamic`.
Lasse Reichstein Nielsen 2017/04/26 09:15:31 This is different from a malformed type, which wou
eernst 2017/05/19 18:49:36 Removed the phrase `which .. annotation`, in line
241
242 ## Changes
243
244 2017-Jan-04: Changed 'static error' to 'compile-time error', which is the
245 phrase that the language specification uses.
246
247 ## Notes
248
249 [^1]: These expressions violate the common style in Dart with respect to
250 spacing and capitalization. That is because the ambiguity implies
251 conflicting requirements, and we do not want to bias the appearance in
252 one of the two directions.
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698