OLD | NEW |
| (Empty) |
1 # Strong mode generic method prototype syntax | |
2 | |
3 This is a summary of the current (as of January 2016) comment-based generic | |
4 method syntax supported by the analyzer strong mode and the Dart Dev Compiler. | |
5 The comment-based syntax essentially uses the proposed actual generic method | |
6 syntax, but wraps it in comments. This allows developers to experiment with | |
7 generic methods while still ensuring that their code runs on all platforms while | |
8 generic methods are still being evaluated for inclusion into the language. | |
9 | |
10 ## Declaring generic method parameters | |
11 | |
12 Generic method parameters are listed using a block comment after the method or | |
13 function name, inside of angle brackets. | |
14 | |
15 ```dart | |
16 // This declares a function which takes two unused generic method parameters | |
17 int f/*<S, T>*/(int x) => 3; | |
18 ``` | |
19 | |
20 As with classes, you can put bounds on type parameters. | |
21 | |
22 ```dart | |
23 // This declares a function which takes two unused generic method parameters | |
24 // The first parameter (S) must extend num | |
25 // The second parameter (T) must extend List<S> | |
26 int f/*<S extends num, T extends List<S>>*/(int x) => 3; | |
27 ``` | |
28 | |
29 Class methods (instance and static) can be declared to take generic parameters | |
30 in the same way. | |
31 | |
32 ```dart | |
33 class C { | |
34 static int f/*<S, T>*/(int x) => 3; | |
35 int m/*<S, T>*/(int x) => 3; | |
36 } | |
37 ``` | |
38 | |
39 Function typed parameters, local functions, and function expressions can also be | |
40 declared to take generic parameters. | |
41 | |
42 ```dart | |
43 // foo takes a generic method as a parameter | |
44 void foo(int f/*<S>*/(int x)) {} | |
45 | |
46 // foo declares a local generic function | |
47 void foo() { | |
48 int f/*<S>*/(int x) => 3; | |
49 return; | |
50 } | |
51 | |
52 // foo binds a generic function expression to a local variable. | |
53 void foo() { | |
54 var x = /*<S>*/(int x) => x; | |
55 } | |
56 ``` | |
57 | |
58 We do not currently support a way to declare a function as returning a generic | |
59 function. This will eventually be supported using something analogous to Dart | |
60 typedefs. | |
61 | |
62 ## Using generic method parameters | |
63 | |
64 The previous examples declared generic method parameters, but did not use them. | |
65 You can use a generic method parameter `T` anywhere that a type is expected in | |
66 Dart by writing a type followed by `/*=T*/`. So for example, `dynamic /*=T*/` | |
67 will be interpreted as `dynamic` by all non-strong mode tools, but will be | |
68 interpreted as `T` by strong mode. In places where it is valid to leave off a | |
69 type, simply writing `/*=T*/` will be interpreted as `dynamic` by non-strong | |
70 mode tools, but will be interpreted as `T` by strong mode. For example: | |
71 | |
72 ```dart | |
73 // foo is a generic method which takes a single generic method parameter S. | |
74 // In strong mode, the parameter x will have type S, and the return type will | |
75 // be S | |
76 // In normal mode, the parameter x will have type dynamic, and the return | |
77 // type will be dynamic. | |
78 dynamic/*=S*/ foo/*<S>*/(dynamic/*=S*/ x) { return x; } | |
79 ``` | |
80 | |
81 This can be written more concisely by leaving off the `dynamic`. | |
82 | |
83 ```dart | |
84 /*=S*/ foo/*<S>*/(/*=S*/ x) {return x;} | |
85 ``` | |
86 | |
87 You can also put a type to the left of the `/*=T/`. This type will be used | |
88 for all non-strong mode tools. For example: | |
89 | |
90 ```dart | |
91 // This method works with `int`, `double`, or `num`. The return type will | |
92 // match the type of the parameters. | |
93 num/*=T*/ pickAtRandom/*<T extends num>*/(num/*=T*/ x, num/*=T*/ y) { ... } | |
94 ``` | |
95 | |
96 | |
97 Note that the generic parameter is in scope in the return type of the function, | |
98 in the argument list of the function, and in the body of the function. When | |
99 declaring local variables and parameters, you can also use the `/*=T*/` syntax w
ith `var`. | |
100 | |
101 ```dart | |
102 // foo is a generic method that takes a single generic parameter S, and a value | |
103 // x of type S | |
104 void foo/*<S>*/(var /*=S*/ x) { | |
105 // In strong mode, y will also have type S | |
106 var /*=S*/ y = x; | |
107 | |
108 // In strong mode, z will also have type S | |
109 dynamic /*=S*/ z = y; | |
110 } | |
111 ``` | |
112 | |
113 Anywhere that a type literal is expected, you can also use the `/*=T*/` syntax t
o | |
114 produce a type literal from the generic method parameter. | |
115 | |
116 ```dart | |
117 void foo/*<S>*/(/*=S*/ x) { | |
118 // In strong mode, s will get the type literal for S | |
119 Type s = dynamic /*=S*/; | |
120 | |
121 // In strong mode, this attempts to cast 3 as type S | |
122 var y = (3 as dynamic /*=S*/); | |
123 } | |
124 ``` | |
125 | |
126 ## Instantiating generic classes with generic method parameters | |
127 | |
128 You can use generic method parameters to instantiate generic classes using the | |
129 same `/*=T*/` syntax. | |
130 | |
131 ```dart | |
132 // foo is a generic method which returns a List<S> in strong mode, | |
133 // but which returns List<dynamic> in normal mode. | |
134 List<dynamic /*=S*/> foo/*<S>*/(/*=S*/ x) { | |
135 // l0 is a list literal whose reified type will be List<S> in strong mode, | |
136 // and List<dynamic> in normal mode. | |
137 var l0 = <dynamic /*=S*/>[x]; | |
138 | |
139 // as above, but with a regular constructor. | |
140 var l1 = new List<dynamic /*=S*/>(); | |
141 return l1; | |
142 } | |
143 ``` | |
144 | |
145 In most cases, the entire type argument list to the generic class can be | |
146 enclosed in parentheses, eliminating the need for explicitly writing `dynamic`. | |
147 | |
148 ```dart | |
149 // This is another way of writing the same code as above | |
150 List/*<S>*/ foo/*<S>*/(/*=S*/ x) { | |
151 // The shorthand syntax is not yet supported for list and map literals | |
152 var l0 = <dynamic /*=S*/>[x]; | |
153 | |
154 // but with regular constructors you can use it | |
155 var l1 = new List/*<S>*/(); | |
156 return l1; | |
157 } | |
158 ``` | |
159 | |
160 ## Instantiating generic methods | |
161 | |
162 Generic methods can be called without passing type arguments. Strong mode will | |
163 attempt to infer the type arguments automatically. If it is unable to do so, | |
164 then the type arguments will be filled in with whatever their declared bounds | |
165 are (by default, `dynamic`). | |
166 | |
167 ```dart | |
168 class C { | |
169 /*=S*/ inferableFromArgument/*<S>*/(/*=S*/ x) { return null;} | |
170 /*=S*/ notInferable/*<S>*/(int x) { return null;} | |
171 } | |
172 | |
173 void main() { | |
174 C c = new C(); | |
175 // This line will produce a type error, because strong mode will infer | |
176 // `int` as the generic argument to fill in for S | |
177 String x = c.inferableFromArgument(3); | |
178 | |
179 // This line will not produce a type error, because strong mode is unable | |
180 // to infer a type and will fill in the type argument with `dynamic`. | |
181 String y = c.notInferable(3); | |
182 } | |
183 ``` | |
184 | |
185 In the case that strong mode cannot infer the generic type arguments, the same | |
186 syntax that was shown above for instantiating generic classes can be used to | |
187 instantiate generic methods explicitly. | |
188 | |
189 ```dart | |
190 void main() { | |
191 C c = new C(); | |
192 // This line will produce a type error, because strong mode will infer | |
193 // `int` as the generic argument to fill in for S | |
194 String x = c.inferableFromArgument(3); | |
195 | |
196 // This line will produce a type error in strong mode, because `int` is | |
197 // explicitly passed in as the argument to use for S | |
198 String y = c.notInferable/*<int>*/(3); | |
199 } | |
200 ``` | |
OLD | NEW |