Chromium Code Reviews| 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 |