Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(747)

Side by Side Diff: docs/newsletter/20170825.md

Issue 3003893002: Newsletter 2017-08-25. (Closed)
Patch Set: Created 3 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 # Dart Language and Library Newsletter
2 2017-08-25
3 @floitschG
4
5 Welcome to the Dart Language and Library Newsletter.
6
7 ## Under Active Development
8 This section provides updates to the areas we are actively working on as part of long-running efforts. Many of these sections have a more detailed explanation i n a previous newsletter.
9
10 ### Better Organization
11 Goal: collect and organize the documents (proposals, ...) the Dart language team produces.
12
13 Since last time, a proposal for an improvement to mixins has been added:
14 https://github.com/dart-lang/sdk/blob/master/docs/language/informal/mixin-declar ation.md
15
16 See below for a summary of this proposal.
17
18 ## Mixins
19 In Dart every class that satisfies some restrictions can be used as a mixin. Whi le this approach is quite elegant, it is not how developers think of mixins. Thi s leads to errors, makes normal classes abnormally brittle (since, in theory, mi nor changes could break their mixin shape) and makes it hard to lift restriction s (such as compositions and requirements on super interfaces).
20
21 We are therefore looking at making mixins separate from normal classes. Instead of introducing a mixin with `class`, one should use `mixin` instead:
22
23 Old:
24 ``` dart
25 class M1 {
26 int foo() => 499;
27 }
28 ```
29
30 New:
31 ``` dart
32 mixin M1 {
33 int foo() => 499;
34 }
35 ```
36
37 Since mixins now have their own syntax, we can fix some of the problems we encou ntered with the `class` syntax. Specifically, invoking `super` methods inside a mixin was a problem. Take for example, a mixin that wants to be mixed in on top of a class that implements `A`, so that it can wrap calls to `A`'s `foo` method. The current specification (which has only been implemented in the VM) uses the `extends` clause to enforce this requirement:
38
39 ``` dart
40 class A {
41 int foo() => 499;
42 }
43
44 // Old style mixin:
45 class M1 extends A {
46 int foo() => super.foo() + 1;
47 }
48
49 class B extends A with M1 {}
50 ```
51
52 The `extends` approach has multiple problems:
53 1. it's unintuitive for our users,
54 2. `A.foo` has to be concrete (since `M1.foo` uses it with a `super.foo` call).
55 3. `M1` can only depend on one supertype,
56 4. there is no obvious way to compose mixins (since `extends` is already taken).
57 5. there is no enforcement, that the class that mixes in `M1` actually has a non -abstract implementation of `A`.
58 6. requiring supertypes that have constructors is not possible, since mixins cur rently must not have constructors.
59
60 The following code snippets illustrate some of these problems with examples:
61
62 ``` dart
63 abstract class A {
64 int foo();
65 }
66
67 class M1 extends A {
68 int foo() => super.foo() + 1; // ERROR: super.foo() is abstract.
69 }
70 ```
71
72 ``` dart
73 abstract class A {
74 int foo();
75 }
76 abstract class B {
77 String bar();
78 }
79
80 // C does *not* know AB (below), nor M1 (also below).
81 class C implements A, B {
82 ...
83 }
84
85 // Workaround class to make it possible to require multiple super classes.
86 class AB implements A, B {
87 int foo() => null;
88 String bar() => null;
89 }
90
91 class M1 extends AB {
92 int foo() => super.foo() + 1;
93 String bar() => super.bar() + "_string";
94 }
95
96 // Intermediate workaround class that adds `AB` on top of C.
97 class _C extends C implements AB {}
98
99 // D needs to extend _C since M1 requires AB as superclass.
100 class D extends _C with M1 {
101 ...
102 }
103 ```
104
105 ``` dart
106 class A {
107 int foo() => 499;
108 }
109
110 class M1 extends A {
111 int foo() => super.foo() + 1;
112 }
113
114 abstract class B implements A {}
115
116 class C extends B with M1 {} // No error, since `B` *implements* A.
117 ```
118
119 All of these problems are easily solved with the specialized `mixin` syntax. Ins tead of using `extends` to specify the supertype requirements, `mixin` declarati ons use `requires`, which can take multiple supertypes.
120
121 Furthermore, since mixins are separate from classes, it is perfectly fine to do `super` invocations (inside the mixin) to abstract methods. Only at mixin time d oes the language check that the required interfaces are fully implemented (or at least the methods that are used by the mixin).
122
123 ``` dart
124 abstract class A {
125 int foo();
126 }
127
128 class B {
129 String bar() => "bar";
130 }
131
132 abstract class C extends B implements A {
133 }
134
135 mixin M1 requires A, B {
136 int foo() => super.foo() + 1;
137 String bar() => super.bar() + "_string";
138 }
139
140 class D extends C with M1 {} // ERROR: foo is not implemented.
141
142 class C2 extends B implements A {
143 int foo() => 42;
144 }
145
146 class D2 extends C2 with M1 {} // OK.
147 }
148 ```
149
150 The current proposal doesn't add any additional features yet, but it lends itsel f to allowing composition with `extends`, and supporting constructors.
151
152 ## Corner Cases
153 A lot of the work the language team does is to discuss and solve corner cases th at most users never encounter. In this section we show two of the more interesti ng ones.
154
155
156 ### Inference vs Manual Types - Part 1.
157 Dart 2.0 strongly relies on type inference to make programming easier. At the sa me time, Dart still allows programmers to write types by hand. This section expl ores some interesting interactions between written and inferred types.
158
159 The following example demonstrates how explicitly writing a type can break a pro gram; or make it work.
160
161 ``` dart
162 void foo(List<int> arg) { ... }
163
164 var x = [1, 2]; // Inferred as `List<int>`.
165 List<Object> y = [1, 2];
166 print(x.runtimeType); // => List<int>.
167 print(y.runtimeType); // => List<Object>.
168 foo(x);
169 foo(y); // Error.
170 x.add("string"); // Error.
171 y.add("string"); // OK.
172 ```
173
174 In the case of `x` the type inference infers that `[1, 2]` is a list of `int`. T he variable `y`, on the other hand, is typed as `List<Object>` and that type is *pushed down* to the expression `[1, 2]`. Those two list-literals have thus two completely different dynamic types despite having the same textual representatio n.
175
176 Both cases are useful: the more precise `List<int>` is used to call `foo`, where as, `y` (being a `List<Object>`) can store objects with types different than `in t`.
177
178 Writing a type, different than the one that type inference finds, can thus chang e the behavior in significant ways (and not necessarily in bad ways). Interestin gly, writing the *exact same type* may also lead to different behavior. That is, given a variable declaration `var x = someExpr`, there are cases where `Type x = someExpr`, with `Type` being the type that would have been inferred for `someE xpr`, leads to a different program.
179
180 I have split this section into two parts, so that developers familiar with stron g mode inference have the opportunity to search for one of these expressions. Th e second part is just after the next section.
181
182 ### Function Types and Covariant Generics
183 To make life easier for developers, Dart allows covariant generics. In short, Da rt says that a `List<Apple>` is a `List<Fruit>`. As long as the value is only re ad out of the list, that is perfectly fine. However, after assigning a `List<App le>` to a `List<Fruit>` we cannot simply add a `Banana` to the list. Statically, adding a Banana is fine (after all, it's a `List<Fruit>`), but dynamically Dart adds a check to ensure that this can't happen.
184
185 ``` dart
186 List<Apple> apples = <Apple>[new Apple()];
187 List<Fruit> fruits = apples; // OK because of covariant generics.
188 fruits.add(new Banana()); // Statically ok, but dynamic error.
189 ```
190
191 In practice this works fine, since most generic types are used as "out" types. T he exceptions, such as `Converter`s (where the first generic is used as input) a re fortunately very rare (although quite annoying when users hit them).
192
193 As mentioned above, Dart adds checks whenever the input might not be the correct type to ensure that the heap stays sound. For example, the `add` method is conc eptually compiled to:
194
195 ``` dart
196 void add(Object o) {
197 if (o is! T) throw new TypeError("$o is not of type $T");
198 /* Add `o` to the list. */
199 }
200 ```
201
202 Some of these checks are easy to find, but some are much trickier:
203
204 ``` dart
205 class A<T> {
206 Function(T) fun;
207 }
208
209 main() {
210 A<int> a = new A<int>();
211 a.fun = (int x) => x + 3;
212 A<Object> a2 = a; // #0
213 var f = a2.fun; // #1, static type: Function(Object).
214 print(f('some_string')); // #2
215 }
216 ```
217
218 At `#0` the `A<int>` is assigned to an `A<Object>`. Because of covariant generic s, this assignment is allowed. The static type of `a2.fun` is `Function(Object)` , which is inferred for `f` at `#1`. However, the function that was stored in `a .fun` is a function that only takes integers. As such, the call at line `#2` mus t not succeed, and Dart must insert checks to ensure that the `x + 3` is never i nvoked with a String.
219
220 The safest and easiest choice would be to insert a check for `int` in the closur e `(int x) => x + 3`. However, that would be too inefficient. Every closure woul d need to check its arguments, even if it is never used in a situation where it might receive arguments of the wrong type. Dart implementations could cheat, and store a hidden bit on closures that enables argument checks or not, but things would get complicated fast.
221
222 There isn't any place to add checks inside `A`. Clearly, users must be able to a ccess the member `fun`, and `A` itself can't know how (and as which type) the re turned member will be used.
223
224 This only leaves the assignment in line `#1`. Dart has to insert a check here th at ensures that the closure that is returned from `A.fun` has the correct type. This is exactly, what Dart 2.0 will do. A dynamic check for the assignment ensur es that the dynamic type of `a2.fun` matches the inferred type of `f`. Since, in this example, `int Function(int)` (the type of the closure) is not assignable t o `dynamic Function(Object)` (the inferred type of `f`), the line `#2` is never reached.
225
226 Afaik this is the only case where a declaration of the form `var x = expr;` fail s dynamically when assigning the evaluated expression to the value of the *infer red* type. It's not that the type inference did a bad job, but that there was no earlier place to inserts the checks that Dart has to do to ensure heap soundnes s.
227
228 Note that this check hasn't been added to DDC, yet.
229
230 ### Inference vs Manual Types - Part 2
231 In part 1 of this section we finished with a claim that there are expressions fo r which writing the inferred type at their declaration point yields a different program than if we had left it off.
232
233 The easiest way to get such an expression is to use the fact that Dart uses down and upwards inference, but doesn't iterate the inference process.
234
235 ``` dart
236 var x = [[499], [false]]; // Inferred to be a List<List<Object>>.
237 List<List<Object>> y = [[499], [false]];
238
239 x[0].add("str"); // Error.
240 y[0].add("str"); // OK.
241 ```
242
243 For `x`, the nested list `[499]` is inferred as `List<int>`, and `[false]` is in ferred as `List<bool>`. The least upper bound of these two types is `List<Object >` and the surrounding list (and thus `x`) is inferred to be `List<List<Object>> `.
244
245 For `y`, the `List<List<Object>>` type is used in the downwards inference to typ e the right-hand side of the assignment. The whole outer list is typed as `List< List<Object>>` (similar to the one for `x`) without even looking at the elements . The type is then continued to be pushed to the entries of the list. Instead of using up inference to infer that `[499]` is a `List<int>` the context already p rovides the type that this expression should have: `List<Object>`. All entries o f the outer list are forced to be `List<Object>`.
246
247 When the program later tries to add a string (`"str"`) to the first list-entries , the one that was inferred to be a `List<int>` has to dynamically reject that v alue, whereas the one that was forced to be `List<Object>` succeeds.
248
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698