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