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 |