| 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 |