Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 ## 1.22.0 | 1 ## 1.22.0 |
| 2 | 2 |
| 3 ### Language | 3 ### Language |
| 4 | 4 |
| 5 * Breaking change: ['Generalized tear-offs'](https://github.com/gbracha/genera lizedTearOffs/blob/master/proposal.md) | 5 * Breaking change: ['Generalized tear-offs'](https://github.com/gbracha/genera lizedTearOffs/blob/master/proposal.md) |
| 6 are no longer supported, and will cause errors. We updated the language spec | 6 are no longer supported, and will cause errors. We updated the language spec |
| 7 and added warnings in 1.21, and are now taking the last step to fully | 7 and added warnings in 1.21, and are now taking the last step to fully |
| 8 de-support them. They were previously supported in the VM only. | 8 de-support them. They were previously supported in the VM only. |
|
filiph
2017/01/26 21:37:51
Would it be possible to add a short alternative to
Bob Nystrom
2017/01/26 22:06:21
I don't think it's worth doing. Almost no one on E
| |
| 9 | 9 |
| 10 * The `assert()` statement has been expanded to support an optional second | 10 * The `assert()` statement has been expanded to support an optional second |
| 11 `message` argument (SDK issue [27342](https://github.com/dart-lang/sdk/issue s/27342)). | 11 `message` argument (SDK issue [27342](https://github.com/dart-lang/sdk/issue s/27342)). |
| 12 | 12 |
| 13 The message is displayed if the assert fails. It can be any object, and it | 13 The message is displayed if the assert fails. It can be any object, and it |
| 14 is accessible as `AssertionError.message`. It can be used to provide more | 14 is accessible as `AssertionError.message`. It can be used to provide more |
| 15 user friendly exception outputs. As an example, the following assert: | 15 user friendly exception outputs. As an example, the following assert: |
| 16 | 16 |
| 17 ```dart | 17 ```dart |
| 18 assert(configFile != null, "Tool config missing. Please see https://goo.gl/k 8iAi for details."); | 18 assert(configFile != null, "Tool config missing. Please see https://goo.gl/k 8iAi for details."); |
| 19 ``` | 19 ``` |
| 20 | 20 |
| 21 would produce the following exception output: | 21 would produce the following exception output: |
| 22 | 22 |
| 23 ``` | 23 ``` |
| 24 Unhandled exception: | 24 Unhandled exception: |
| 25 'file:///Users/mit/tmp/tool/bin/main.dart': Failed assertion: line 9 pos 10: | 25 'file:///Users/mit/tmp/tool/bin/main.dart': Failed assertion: line 9 pos 10: |
| 26 'configFile != null': Tool config missing. Please see https://goo.gl/k8iAi f or details. | 26 'configFile != null': Tool config missing. Please see https://goo.gl/k8iAi f or details. |
| 27 #0 _AssertionError._doThrowNew (dart:core-patch/errors_patch.dart:33) | 27 #0 _AssertionError._doThrowNew (dart:core-patch/errors_patch.dart:33) |
| 28 #1 _AssertionError._throwNew (dart:core-patch/errors_patch.dart:29) | 28 #1 _AssertionError._throwNew (dart:core-patch/errors_patch.dart:29) |
| 29 #2 main (file:///Users/mit/tmp/tool/bin/main.dart:9:10) | 29 #2 main (file:///Users/mit/tmp/tool/bin/main.dart:9:10) |
| 30 ``` | 30 ``` |
| 31 | 31 |
| 32 * The `Null` type has been moved to the bottom of the type hierarchy. As such, | 32 * The `Null` type has been moved to the bottom of the type hierarchy. As such, |
| 33 it is considered a subtype of every other type. | 33 it is considered a subtype of every other type. The `null` *literal* was |
| 34 always treated as a bottom type. Now the named class `Null` is too: | |
| 34 | 35 |
| 35 Examples: | 36 ```dart |
| 37 const empty = <Null>[]; | |
| 38 | |
| 39 String concatenate(List<String> parts) => parts.join(); | |
| 40 int sum(List<int> numbers) => numbers.fold(0, (sum, n) => sum + n); | |
| 41 | |
| 42 concatenate(empty); // OK. | |
| 43 sum(empty); // OK. | |
| 36 ``` | 44 ``` |
| 37 Null foo() => null; | |
| 38 int x = foo(); | |
| 39 String x = foo(); | |
| 40 | 45 |
| 41 List<Null> bar() => <Null>[]; | 46 * Introduce `covariant` modifier on parameters. It indicates that the |
| 42 List<int> = bar(); | 47 parameter (and the corresponding parameter in any method that overrides it) |
| 43 List<String> = bar(); | 48 has looser override rules. In strong mode, these require a runtime type |
| 49 check to maintain soundness, but enable an architectural pattern that is | |
| 50 useful in some code. | |
| 51 | |
| 52 It lets you specialize a family of classes together, like so: | |
| 53 | |
| 54 ```dart | |
| 55 abstract class Predator { | |
| 56 void chaseAndEat(covariant Prey p); | |
| 57 } | |
| 58 | |
| 59 abstract class Prey {} | |
| 60 | |
| 61 class Mouse extends Prey {} | |
| 62 | |
| 63 class Seal extends Prey {} | |
| 64 | |
| 65 class Cat extends Predator { | |
| 66 void chaseAndEat(Mouse m) => ... | |
| 67 } | |
| 68 | |
| 69 class Orca extends Predator { | |
| 70 void chaseAndEat(Seal s) => ... | |
| 71 } | |
| 44 ``` | 72 ``` |
| 45 | 73 |
| 74 This isn't statically safe, because you could do: | |
| 75 | |
| 76 ```dart | |
| 77 Predator predator = new Cat(); // Upcast. | |
| 78 predator(new Seal()); // Cats can't eat seals! | |
| 79 ``` | |
| 80 | |
| 81 To preserve soundness in strong mode, in the body of a method that uses a | |
| 82 covariant override (here, `Cat.chaseAndEat()`), the compiler automatically | |
| 83 inserts a check that the parameter is of the expected type. So the compiler | |
| 84 gives you something like: | |
| 85 | |
| 86 ```dart | |
| 87 class Cat extends Predator { | |
| 88 void chaseAndEat(o) { | |
| 89 var m = o as Mouse; | |
| 90 ... | |
| 91 } | |
| 92 } | |
| 93 ``` | |
| 94 | |
| 95 Spec mode allows this unsound behavior on all parameters, even though users | |
| 96 rarely rely on it. Strong mode disallowed it initially. Now, strong mode | |
| 97 lets you opt into this behavior in the places where you do want it by using | |
| 98 this modifier. Outside of strong mode, the modifier is ignored. | |
| 99 | |
| 100 * Change instantiate-to-bounds rules for generic type parameters when running | |
| 101 in strong mode. If you leave off the type parameters from a generic type, we | |
| 102 need to decide what to fill them in with. Dart 1.0 says just use `dynamic`, | |
| 103 but that isn't sound: | |
| 104 | |
| 105 ```dart | |
| 106 class Abser<T extends num> { | |
| 107 void absThis(T n) { n.abs(); } | |
| 108 } | |
| 109 | |
| 110 var a = new Abser(); // Abser<dynamic>. | |
| 111 a.absThis("not a num"); | |
| 112 ``` | |
| 113 | |
| 114 We want the body of `absThis()` to be able to safely assume `n` is at | |
| 115 least a `num` -- that's why there's a constraint on T, after all. Implicitly | |
| 116 using `dynamic` as the type parameter in this example breaks that. | |
| 117 | |
| 118 Instead, strong mode uses the bound. In the above example, it fills it in | |
| 119 with `num`, and then the second line where a string is passed becomes a | |
| 120 static error. | |
| 121 | |
| 122 However, there are some cases where it is hard to figure out what that | |
| 123 default bound should be: | |
| 124 | |
| 125 ```dart | |
| 126 class RuhRoh<T extends Comparable<T>> {} | |
| 127 ``` | |
| 128 | |
| 129 Strong mode's initial behavior sometimes produced surprising, unintended | |
| 130 results. For 1.22, we take a simpler approach and then report an error if | |
| 131 a good default type argument can't be found. | |
| 132 | |
| 133 ### Core libraries | |
| 134 | |
| 135 * Define `FutureOr<T>` for code that works with either a future or an | |
| 136 immediate value of some type. For example, say you do a lot of text | |
| 137 manipulation, and you want a handy function to chain a bunch of them: | |
| 138 | |
| 139 ```dart | |
| 140 typedef String StringSwizzler(String input); | |
| 141 | |
| 142 String swizzle(String input, List<StringSwizzler> swizzlers) { | |
| 143 var result = input; | |
| 144 for (var swizzler in swizzlers) { | |
| 145 result = swizzler(result); | |
| 146 } | |
| 147 | |
| 148 return result; | |
| 149 } | |
| 150 ``` | |
| 151 | |
| 152 This works fine: | |
| 153 | |
| 154 ```dart | |
| 155 main() { | |
| 156 var result = swizzle("input", [ | |
| 157 (s) => s.toUpperCase(), | |
| 158 (s) => () => s * 2) | |
| 159 ]); | |
| 160 print(result); // "INPUTINPUT". | |
| 161 } | |
| 162 ``` | |
| 163 | |
| 164 Later, you realize you'd also like to support swizzlers that are | |
| 165 asynchronous (maybe they look up synonyms for words online). You could make | |
| 166 your API strictly synchronous, but then users of simple synchronous | |
|
filiph
2017/01/26 21:37:51
"You could make your API strictly synchronous" --
Bob Nystrom
2017/01/26 22:06:21
Good catch! Done.
| |
| 167 swizzlers have to manually wrap the return value in a `Future.value()`. | |
| 168 Ideally, your `swizzle()` function would be "polymorphic over asynchrony". | |
| 169 It would allow both synchronous and asynchronous swizzlers. Because `await` | |
| 170 accepts immediate values, it is easy to implement this dynamically: | |
| 171 | |
| 172 ```dart | |
| 173 Future<String> swizzle(String input, List<StringSwizzler> swizzlers) async { | |
| 174 var result = input; | |
| 175 for (var swizzler in swizzlers) { | |
| 176 result = await swizzler(result); | |
| 177 } | |
| 178 | |
| 179 return result; | |
| 180 } | |
| 181 | |
| 182 main() async { | |
| 183 var result = swizzle("input", [ | |
| 184 (s) => s.toUpperCase(), | |
| 185 (s) => new Future.delayed(new Duration(milliseconds: 40), () => s * 2) | |
| 186 ]); | |
| 187 print(await result); | |
| 188 } | |
| 189 ``` | |
| 190 | |
| 191 What should the declared return type on StringSwizzler be? In the past, you | |
| 192 had to use `dynamic` or `Object`, but that doesn't tell the user much. Now, | |
| 193 you can do: | |
| 194 | |
| 195 ```dart | |
| 196 typedef FutureOr<String> StringSwizzler(String input); | |
| 197 ``` | |
| 198 | |
| 199 Like the name implies, `FutureOr<String>` is a union type. It can be a | |
| 200 `String` or a `Future<String>`, but not anything else. In this case, that's | |
| 201 not super useful beyond just stating a more precise type for readers of the | |
| 202 code. It does give you a little better error checking in code that uses the | |
| 203 result of that. | |
| 204 | |
| 205 `FutureOr<T>` becomes really important in *generic* methods like | |
| 206 `Future.then()`. In those cases, having the type system understand this | |
| 207 magical union type helps type inference figure out the type argument of | |
| 208 `then()` based on the closure you pass it. | |
| 209 | |
| 210 Previously, strong mode had hard-coded rules for handling `Future.then()` | |
| 211 specifically. `FutureOr<T>` exposes that functionality so third-party APIs | |
| 212 can take advantage of it too. | |
| 213 | |
| 46 ### Tool changes | 214 ### Tool changes |
| 47 | 215 |
| 48 * Dart2Js | 216 * Dart2Js |
| 49 | 217 |
| 50 * Remove support for (long-time deprecated) mixin typedefs. | 218 * Remove support for (long-time deprecated) mixin typedefs. |
| 51 | 219 |
| 52 * Pub | 220 * Pub |
| 53 | 221 |
| 54 * Avoid using a barback asset server for executables unless they actually use | 222 * Avoid using a barback asset server for executables unless they actually use |
| 55 transformers. This makes precompilation substantially faster, produces | 223 transformers. This makes precompilation substantially faster, produces |
| (...skipping 1433 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1489 they will keep the Dart process alive until they time out. This fixes the | 1657 they will keep the Dart process alive until they time out. This fixes the |
| 1490 handling of persistent connections. Previously, the client would shut down | 1658 handling of persistent connections. Previously, the client would shut down |
| 1491 immediately after a request. | 1659 immediately after a request. |
| 1492 | 1660 |
| 1493 * **Breaking change:** `HttpServer` no longer compresses all traffic by | 1661 * **Breaking change:** `HttpServer` no longer compresses all traffic by |
| 1494 default. The new `autoCompress` property can be set to `true` to re-enable | 1662 default. The new `autoCompress` property can be set to `true` to re-enable |
| 1495 compression. | 1663 compression. |
| 1496 | 1664 |
| 1497 * `dart:isolate`: `Isolate.spawnUri` added the optional `packageRoot` argument, | 1665 * `dart:isolate`: `Isolate.spawnUri` added the optional `packageRoot` argument, |
| 1498 which controls how it resolves `package:` URIs. | 1666 which controls how it resolves `package:` URIs. |
| OLD | NEW |