| OLD | NEW |
| 1 --- | 1 --- |
| 2 layout: default | 2 layout: default |
| 3 title: "Milestone 1 Language Changes" | 3 title: "Milestone 1 Language Changes" |
| 4 rel: | 4 rel: |
| 5 author: bob-nystrom | 5 author: bob-nystrom |
| 6 description: "A brief introduction to some of the language changes we are making
heading into our next milestone." | 6 description: "A brief introduction to some of the language changes planned for t
he M1 milestone." |
| 7 --- | 7 --- |
| 8 | 8 |
| 9 # Milestone 1 Language Changes | 9 # Milestone 1 Language Changes |
| 10 | 10 |
| 11 Right now as we near our “Milestone 1” release, we are making a slew of fun lang
uage changes. There are tracking bugs in the repo for all of them, but I wanted
to run through them here and try to provide some context and rationale where I c
an. | 11 Right now as we near our "Milestone 1" release, we are making a slew of fun lang
uage changes. There are tracking bugs in the repo for all of them, but I wanted
to run through them here and try to provide some context and rationale where I c
an. |
| 12 | 12 |
| 13 ## Contents | 13 ## Contents |
| 14 | 14 |
| 15 1. [First class types](#first-class-types) | 15 1. [First class types](#first-class-types) |
| 16 1. [No explicit interfaces](#no-explicit-interfaces) | 16 1. [No explicit interfaces](#no-explicit-interfaces) |
| 17 1. [No "+" on String](#no--on-string) | 17 1. [No "+" on String](#no--on-string) |
| 18 1. [No throwing `null`](#no-throwing-null) | 18 1. [No throwing `null`](#no-throwing-null) |
| 19 1. [The “as” cast operator](#the-as-cast-operator) | 19 1. [The "as" cast operator](#the-as-cast-operator) |
| 20 1. [Cascades](#cascades) | 20 1. [Cascades](#cascades) |
| 21 1. [Lazy static initialization](#lazy-static-initialization) | 21 1. [Lazy static initialization](#lazy-static-initialization) |
| 22 1. [Support “const” modifier for variables](#support-const-modifier-for-variable
s) | 22 1. [Support "const" modifier for variables](#support-const-modifier-for-variable
s) |
| 23 1. [Syntax for defining operators](#syntax-for-defining-operators) | 23 1. [Syntax for defining operators](#syntax-for-defining-operators) |
| 24 1. [Split library scope and import scope](#split-library-scope-and-import-scope) | 24 1. [Split library scope and import scope](#split-library-scope-and-import-scope) |
| 25 1. [Revised switch](#revised-switch) | 25 1. [Revised switch](#revised-switch) |
| 26 1. [Selective imports](#selective-imports) | 26 1. [Selective imports](#selective-imports) |
| 27 1. [Re-export](#re-export) | 27 1. [Re-export](#re-export) |
| 28 1. [Static methods are constants](#static-methods-are-constants) | 28 1. [Static methods are constants](#static-methods-are-constants) |
| 29 1. [New catch syntax](#new-catch-syntax) | 29 1. [New catch syntax](#new-catch-syntax) |
| 30 1. [Getter and setter definition syntax](#getter-and-setter-definition-syntax) | 30 1. [Getter and setter definition syntax](#getter-and-setter-definition-syntax) |
| 31 1. [Conclusion](#conclusion) | 31 1. [Conclusion](#conclusion) |
| 32 {:.toc} | 32 {:.toc} |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 78 {% endhighlight %} | 78 {% endhighlight %} |
| 79 | 79 |
| 80 Note that it says *implements*, not *extends*. We are not subclassing Person, we
are just saying that Imposter supports all of the public methods Person defines
and that we can pass it to anything that expects a Person. | 80 Note that it says *implements*, not *extends*. We are not subclassing Person, we
are just saying that Imposter supports all of the public methods Person defines
and that we can pass it to anything that expects a Person. |
| 81 | 81 |
| 82 Dart also supports abstract methods in classes. Given abstract methods and impli
cit interfaces, there’s no actual need for an explicit interface construct: just
make a class where all of its methods are abstract, and then implement its impl
icit interface. | 82 Dart also supports abstract methods in classes. Given abstract methods and impli
cit interfaces, there’s no actual need for an explicit interface construct: just
make a class where all of its methods are abstract, and then implement its impl
icit interface. |
| 83 | 83 |
| 84 Getting rid of interfaces simplifies the language while also removing some of th
e limitations that interfaces had: unlike classes, they couldn’t define static m
embers for example. It also simplifies designing an API: you no longer have thin
k about whether you should define something as an interface or an abstract class
. | 84 Getting rid of interfaces simplifies the language while also removing some of th
e limitations that interfaces had: unlike classes, they couldn’t define static m
embers for example. It also simplifies designing an API: you no longer have thin
k about whether you should define something as an interface or an abstract class
. |
| 85 | 85 |
| 86 ## No "+" on String | 86 ## No "+" on String |
| 87 | 87 |
| 88 A deeply contentious issue, Dart no longer allows using the “+” operator on stri
ngs. So no more: | 88 A deeply contentious issue, Dart no longer allows using the "+" operator on stri
ngs. So no more: |
| 89 | 89 |
| 90 {% highlight dart %} | 90 {% highlight dart %} |
| 91 print("Hi, " + yourName); | 91 print("Hi, " + yourName); |
| 92 {% endhighlight %} | 92 {% endhighlight %} |
| 93 | 93 |
| 94 There seem to be as many reasons for (and against) this change as there are Dart
team members, but the two motivators I see repeatedly are: | 94 There seem to be as many reasons for (and against) this change as there are Dart
team members, but the two motivators I see repeatedly are: |
| 95 | 95 |
| 96 1. It’s a source of bugs and surprising behavior because it’s not symmetric and
is sensitive to operator precedence. `print("1 + 2 = " + 1 + 2)` doesn’t do what
some people might expect and `"a" + 1` and `1 + "a"` have unpleasantly differen
t behavior. | 96 1. It’s a source of bugs and surprising behavior because it’s not symmetric and
is sensitive to operator precedence. `print("1 + 2 = " + 1 + 2)` doesn’t do what
some people might expect and `"a" + 1` and `1 + "a"` have unpleasantly differen
t behavior. |
| 97 | 97 |
| 98 2. Naïve code that uses it heavily can have poor performance with simple interna
l string implementations. If you do something like use `+=` in a loop to build u
p a long string, and you’re running on an implementation that doesn’t have sophi
sticated code for handling strings you can end up doing a lot of wasted allocati
ons. | 98 2. Naïve code that uses it heavily can have poor performance with simple interna
l string implementations. If you do something like use `+=` in a loop to build u
p a long string, and you’re running on an implementation that doesn’t have sophi
sticated code for handling strings you can end up doing a lot of wasted allocati
ons. |
| 99 | 99 |
| 100 So, without `+`, what should you do when you need to staple a couple of strings
to each other? Fortunately, [Seth has your back here](http://news.dartlang.org/2
012/06/vm-to-remove-support-for-string.html). | 100 So, without `+`, what should you do when you need to staple a couple of strings
to each other? Fortunately, [Seth has your back here](http://news.dartlang.org/2
012/06/vm-to-remove-support-for-string.html). |
| 101 | 101 |
| 102 ([Tracking issue #3707](http://dartbug.com/3707)) | 102 ([Tracking issue #3707](http://dartbug.com/3707)) |
| 103 | 103 |
| 104 ## No throwing `null` | 104 ## No throwing `null` |
| 105 | 105 |
| 106 Dart now considers it a dynamic error to throw `null`. In almost every case wher
e `null` is thrown, it’s a programmer error: they meant to throw some exception
object but accidentally got a `null` instead. By disallowing this, we can detect
that error earlier and help the user fix their code. | 106 Dart now considers it a dynamic error to throw `null`. In almost every case wher
e `null` is thrown, it’s a programmer error: they meant to throw some exception
object but accidentally got a `null` instead. By disallowing this, we can detect
that error earlier and help the user fix their code. |
| 107 | 107 |
| 108 *Allowing* `null` to be thrown, on the other hand, forces programmers to think a
bout what kinds of `catch` clauses will match it. Will a `catch` clause of any t
ype select `null`? None of them? Just `var ex`? There isn’t an obvious intuitive
correct behavior here, so users are likely to be confused. | 108 *Allowing* `null` to be thrown, on the other hand, forces programmers to think a
bout what kinds of `catch` clauses will match it. Will a `catch` clause of any t
ype select `null`? None of them? Just `var ex`? There isn’t an obvious intuitive
correct behavior here, so users are likely to be confused. |
| 109 | 109 |
| 110 ([Tracking issue #2940](http://dartbug.com/2940)) | 110 ([Tracking issue #2940](http://dartbug.com/2940)) |
| 111 | 111 |
| 112 ## The “as” cast operator | 112 ## The "as" cast operator |
| 113 | 113 |
| 114 Dart now has an infix operator `as` that lets you cast an expression to a given
type without having to declare a type annotated local variable. Where before, if
you wanted to indicate some extra knowledge about the types of objects in your
code, you had to do: | 114 Dart now has an infix operator `as` that lets you cast an expression to a given
type without having to declare a type annotated local variable. Where before, if
you wanted to indicate some extra knowledge about the types of objects in your
code, you had to do: |
| 115 | 115 |
| 116 {% highlight dart %} | 116 {% highlight dart %} |
| 117 ButtonElement button = query('button'); | 117 ButtonElement button = query('button'); |
| 118 button.value = 1234; | 118 button.value = 1234; |
| 119 {% endhighlight %} | 119 {% endhighlight %} |
| 120 | 120 |
| 121 Now you can do: | 121 Now you can do: |
| 122 | 122 |
| (...skipping 19 matching lines...) Expand all Loading... |
| 142 | 142 |
| 143 or the tedium of having to define a local variable: | 143 or the tedium of having to define a local variable: |
| 144 | 144 |
| 145 {% highlight dart %} | 145 {% highlight dart %} |
| 146 var toggleButton = query('#my-form').query('button'); | 146 var toggleButton = query('#my-form').query('button'); |
| 147 toggleButton.classes.add('toggle'); | 147 toggleButton.classes.add('toggle'); |
| 148 toggleButton.text = 'Click Me!'; | 148 toggleButton.text = 'Click Me!'; |
| 149 toggleButton.labels.add(toggleLabel); | 149 toggleButton.labels.add(toggleLabel); |
| 150 {% endhighlight %} | 150 {% endhighlight %} |
| 151 | 151 |
| 152 Some APIs, like jQuery in JavaScript or StringBuffer in Java get around this by
using “fluent interfaces”: their methods return this so you can chain calls dire
ctly. But that forces API designers to choose between returning a useful value o
r allowing chaining: they can’t support both. It also forces all APIs to be desi
gned up front to support this. | 152 Some APIs, like jQuery in JavaScript or StringBuffer in Java get around this by
using "fluent interfaces": their methods return this so you can chain calls dire
ctly. But that forces API designers to choose between returning a useful value o
r allowing chaining: they can’t support both. It also forces all APIs to be desi
gned up front to support this. |
| 153 | 153 |
| 154 To remedy that, Smalltalk pioneered something called “message cascades” which Da
rt has adopted. These let you sequence a series of method calls that all apply t
o the same receiver, like so: | 154 To remedy that, Smalltalk pioneered something called "message cascades" which Da
rt has adopted. These let you sequence a series of method calls that all apply t
o the same receiver, like so: |
| 155 | 155 |
| 156 {% highlight dart %} | 156 {% highlight dart %} |
| 157 query('#my-form').query('button') | 157 query('#my-form').query('button') |
| 158 ..classes.add('toggle') | 158 ..classes.add('toggle') |
| 159 ..text = 'Click Me!' | 159 ..text = 'Click Me!' |
| 160 ..labels.add(toggleLabel); | 160 ..labels.add(toggleLabel); |
| 161 {% endhighlight %} | 161 {% endhighlight %} |
| 162 | 162 |
| 163 Here, everything after `..` is called on the result of the expression before the
first `..`. What’s nice is that this works with every API, not just ones explic
itly implemented using a fluent pattern. | 163 Here, everything after `..` is called on the result of the expression before the
first `..`. What’s nice is that this works with every API, not just ones explic
itly implemented using a fluent pattern. |
| 164 | 164 |
| 165 ([Tracking issue #2501](http://dartbug.com/2501)) | 165 ([Tracking issue #2501](http://dartbug.com/2501)) |
| 166 | 166 |
| 167 ## Lazy static initialization | 167 ## Lazy static initialization |
| 168 | 168 |
| 169 Formerly, Dart required that all `static final` fields (or `final` top-level var
iables) be initialized with constant expressions. In other words, they could onl
y be used to define compile-time constants. That significantly limits their use,
preventing, for example, this field: | 169 Formerly, Dart required that all `static final` fields (or `final` top-level var
iables) be initialized with constant expressions. In other words, they could onl
y be used to define compile-time constants. That significantly limits their use,
preventing, for example, this field: |
| 170 | 170 |
| 171 {% highlight dart %} | 171 {% highlight dart %} |
| 172 class Stopwatch { | 172 class Stopwatch { |
| 173 static final startTime = new DateTime.now(); | 173 static final startTime = new DateTime.now(); |
| 174 } | 174 } |
| 175 {% endhighlight %} | 175 {% endhighlight %} |
| 176 | 176 |
| 177 We’ve decided to loosen that so that `static final` fields and `final` top-level
variables can be initialized using *any* expression. These will then be lazy in
itialized the first time the variable is accessed. This is closer to behavior us
ers coming from Java or C# expect given Dart’s similar syntax. | 177 We’ve decided to loosen that so that `static final` fields and `final` top-level
variables can be initialized using *any* expression. These will then be lazy in
itialized the first time the variable is accessed. This is closer to behavior us
ers coming from Java or C# expect given Dart’s similar syntax. |
| 178 | 178 |
| 179 ([Tracking issue #3557](http://dartbug.com/3557)) | 179 ([Tracking issue #3557](http://dartbug.com/3557)) |
| 180 | 180 |
| 181 ## Support “const” modifier for variables | 181 ## Support "const" modifier for variables |
| 182 | 182 |
| 183 The above change is more flexible, but it leaves an open issue: how do you defin
e a `static final` field or `final` top-level variable that *is* constant, and t
hat can be used in constant expressions? With this looser behavior, you lose the
ability to do: | 183 The above change is more flexible, but it leaves an open issue: how do you defin
e a `static final` field or `final` top-level variable that *is* constant, and t
hat can be used in constant expressions? With this looser behavior, you lose the
ability to do: |
| 184 | 184 |
| 185 {% highlight dart %} | 185 {% highlight dart %} |
| 186 class SomeClass { | 186 class SomeClass { |
| 187 static final someConstant = 123; | 187 static final someConstant = 123; |
| 188 static final aConstList = const [someConstant]; | 188 static final aConstList = const [someConstant]; |
| 189 } | 189 } |
| 190 {% endhighlight %} | 190 {% endhighlight %} |
| 191 | 191 |
| 192 Since `someConstant` doesn’t *have* to be constant now, it may not be, which mea
ns it can’t be used in a constant expression like `const [someConstant]`. To fix
that, Dart will also allow `const` as a modifier for variables. This way you ca
n indicate which top-level `final` variables and `static final` fields are const
ant and which are lazy-initialized non-constant: | 192 Since `someConstant` doesn’t *have* to be constant now, it may not be, which mea
ns it can’t be used in a constant expression like `const [someConstant]`. To fix
that, Dart will also allow `const` as a modifier for variables. This way you ca
n indicate which top-level `final` variables and `static final` fields are const
ant and which are lazy-initialized non-constant: |
| 193 | 193 |
| 194 {% highlight dart %} | 194 {% highlight dart %} |
| 195 class SomeClass { | 195 class SomeClass { |
| 196 static const someConstant = 123; // OK | 196 static const someConstant = 123; // OK |
| 197 static final startTime = new DateTime.now(); // OK too | 197 static final startTime = new DateTime.now(); // OK too |
| 198 static const aConstList = const [someConstant]; // also OK | 198 static const aConstList = const [someConstant]; // also OK |
| 199 } | 199 } |
| 200 {% endhighlight %} | 200 {% endhighlight %} |
| 201 | 201 |
| 202 ([Tracking issue #3549](http://dartbug.com/3549)) | 202 ([Tracking issue #3549](http://dartbug.com/3549)) |
| 203 | 203 |
| 204 ## Syntax for defining operators | 204 ## Syntax for defining operators |
| 205 | 205 |
| 206 This is a pretty minor change. The previous spec used `equals` and `negate` as s
pecial identifiers for defining equality and unary negation operators, respectiv
ely. That raises some confusing questions like “Can you also call those methods
by name?” To simplify that, we will just use `==` and `-` to define those operat
ors. We’ll disambiguate unary and binary minus by their arity (number of paramet
ers). | 206 This is a pretty minor change. The previous spec used `equals` and `negate` as s
pecial identifiers for defining equality and unary negation operators, respectiv
ely. That raises some confusing questions like "Can you also call those methods
by name?" To simplify that, we will just use `==` and `-` to define those operat
ors. We’ll disambiguate unary and binary minus by their arity (number of paramet
ers). |
| 207 | 207 |
| 208 {% highlight dart %} | 208 {% highlight dart %} |
| 209 class MagicNumber { | 209 class MagicNumber { |
| 210 bool operator ==(other) => … | 210 bool operator ==(other) => … |
| 211 MagicNumber operator -() => … // unary negate | 211 MagicNumber operator -() => … // unary negate |
| 212 MagicNumber operator -(other) => … // infix minus | 212 MagicNumber operator -(other) => … // infix minus |
| 213 } | 213 } |
| 214 {% endhighlight %} | 214 {% endhighlight %} |
| 215 | 215 |
| 216 ([Tracking issue #3765](http://dartbug.com/3765)) | 216 ([Tracking issue #3765](http://dartbug.com/3765)) |
| 217 | 217 |
| 218 ## Split library scope and import scope | 218 ## Split library scope and import scope |
| 219 | 219 |
| 220 Stephen [explains the rationale for this change](http://code.google.com/p/dart/i
ssues/detail?id=1285) better than I can: | 220 Stephen [explains the rationale for this change](http://code.google.com/p/dart/i
ssues/detail?id=1285) better than I can: |
| 221 | 221 |
| 222 > There is a problem that a name may be defined by `#import` or by a definition
in the current library. A change to the imported library can break a program by
introducing a clashing name. | 222 > There is a problem that a name may be defined by `#import` or by a definition
in the current library. A change to the imported library can break a program by
introducing a clashing name. |
| 223 | 223 |
| 224 What he means here is consider you have this program: | 224 What he means here is consider you have this program: |
| 225 | 225 |
| 226 {% highlight dart %} | 226 {% highlight dart %} |
| 227 #import('somelib.dart'); | 227 #import('somelib.dart'); |
| 228 | 228 |
| 229 foo() => print('foo!'); | 229 foo() => print('foo!'); |
| 230 main() => foo(); | 230 main() => foo(); |
| 231 {% endhighlight %} | 231 {% endhighlight %} |
| 232 | 232 |
| 233 Later, you upgrade to the latest greatest version of “somelib” and discover to y
our dismay that they’ve added a `foo()` function to it. Currently, this breaks y
our code since those names are in the same namespace and collide. Stephen’s prop
osal is: | 233 Later, you upgrade to the latest greatest version of "somelib" and discover to y
our dismay that they’ve added a `foo()` function to it. Currently, this breaks y
our code since those names are in the same namespace and collide. Stephen’s prop
osal is: |
| 234 | 234 |
| 235 > I suggest that imports happen into a scope surrounding the current library. T
his would reduce a clash in an imported library to an override warning and at th
e same time ensure the current library's behaviour did not change. | 235 > I suggest that imports happen into a scope surrounding the current library. T
his would reduce a clash in an imported library to an override warning and at th
e same time ensure the current library's behaviour did not change. |
| 236 | 236 |
| 237 In other words, with this change, your local `foo()` will *shadow* the new one i
n “somelib” instead of colliding, and your code does the right thing. | 237 In other words, with this change, your local `foo()` will *shadow* the new one i
n "somelib" instead of colliding, and your code does the right thing. |
| 238 | 238 |
| 239 In addition, we’ve removed another annoying restriction. Previously, if you impo
rted the same name from two different libraries (say Node from dart:html and dar
tdoc) then you would get a name collision error *even if you didn’t use that nam
e anywhere in your code.* Now, Dart will only worry about name collisions for na
mes that you actually use. You only get an error if there is an ambiguous *use*
of a name in your code. | 239 In addition, we’ve removed another annoying restriction. Previously, if you impo
rted the same name from two different libraries (say Node from dart:html and dar
tdoc) then you would get a name collision error *even if you didn’t use that nam
e anywhere in your code.* Now, Dart will only worry about name collisions for na
mes that you actually use. You only get an error if there is an ambiguous *use*
of a name in your code. |
| 240 | 240 |
| 241 ([Tracking issue #1285](http://dartbug.com/1285)) | 241 ([Tracking issue #1285](http://dartbug.com/1285)) |
| 242 | 242 |
| 243 ## Revised switch | 243 ## Revised switch |
| 244 | 244 |
| 245 In its original incarnation, Dart’s `switch` statement worked like JavaScript’s
and not Java’s. It was essentially syntactic sugar for a series of chained `if-e
lse` statments. For example, this: | 245 In its original incarnation, Dart’s `switch` statement worked like JavaScript’s
and not Java’s. It was essentially syntactic sugar for a series of chained `if-e
lse` statments. For example, this: |
| 246 | 246 |
| 247 {% highlight dart %} | 247 {% highlight dart %} |
| (...skipping 14 matching lines...) Expand all Loading... |
| 262 hasBeard = true; | 262 hasBeard = true; |
| 263 } else { | 263 } else { |
| 264 hasBeard = false; | 264 hasBeard = false; |
| 265 } | 265 } |
| 266 {% endhighlight %} | 266 {% endhighlight %} |
| 267 | 267 |
| 268 Note that in the desugared `if-else` form, it ends up calling the equality (`==`
) operator. This operator can be overloaded for your own types, so this has an i
mportant consequence. With these semantics, a `switch` statement *must* be handl
ed exactly like a series of chained `if-else` statements. | 268 Note that in the desugared `if-else` form, it ends up calling the equality (`==`
) operator. This operator can be overloaded for your own types, so this has an i
mportant consequence. With these semantics, a `switch` statement *must* be handl
ed exactly like a series of chained `if-else` statements. |
| 269 | 269 |
| 270 This has unpleasant optimization implications. In languages like C and Java, a `
switch` statement can only be used with numeric values. Compilers can and do com
pile down a `switch` statement to either a jump table that directly selects a ca
se based on the value, or to a binary search of the cases, or some mixed heurist
ic of the two. In other words, in those languages selecting the right `case` for
a `switch` can have `O(1)` or `O(log n)` performance (where `n` is the number o
f cases). In Dart, it’s always `O(n)`. | 270 This has unpleasant optimization implications. In languages like C and Java, a `
switch` statement can only be used with numeric values. Compilers can and do com
pile down a `switch` statement to either a jump table that directly selects a ca
se based on the value, or to a binary search of the cases, or some mixed heurist
ic of the two. In other words, in those languages selecting the right `case` for
a `switch` can have `O(1)` or `O(log n)` performance (where `n` is the number o
f cases). In Dart, it’s always `O(n)`. |
| 271 | 271 |
| 272 So we’ve decided to restrict `switch` in Dart. Instead of calling a user-defined
equality operator, we only allow you to switch on numbers, strings, and constan
t objects. This gives compilers enough flexibility to compile them more efficien
tly. Since constant objects are canonicalized, they can be reliably compared pur
ely based on *identity*, so they don’t have the problem of allowing user-defined
equality operators. This lets you still switch on user-defined “enum-like” obje
cts. | 272 So we’ve decided to restrict `switch` in Dart. Instead of calling a user-defined
equality operator, we only allow you to switch on numbers, strings, and constan
t objects. This gives compilers enough flexibility to compile them more efficien
tly. Since constant objects are canonicalized, they can be reliably compared pur
ely based on *identity*, so they don’t have the problem of allowing user-defined
equality operators. This lets you still switch on user-defined "enum-like" obje
cts. |
| 273 | 273 |
| 274 ## Selective imports | 274 ## Selective imports |
| 275 | 275 |
| 276 Library imports were a blunt instrument in Dart: you either imported every singl
e name from a library or none of them. If a single name in that library collides
with another one you’re importing, your only recourse is to import that entire
library with a prefix. | 276 Library imports were a blunt instrument in Dart: you either imported every singl
e name from a library or none of them. If a single name in that library collides
with another one you’re importing, your only recourse is to import that entire
library with a prefix. |
| 277 | 277 |
| 278 Now, you’ll be given finer grained control. If you do: | 278 Now, you’ll be given finer grained control. If you do: |
| 279 | 279 |
| 280 {% highlight dart %} | 280 {% highlight dart %} |
| 281 #import('somelib.dart', show: ['foo', 'bar']); | 281 #import('somelib.dart', show: ['foo', 'bar']); |
| 282 {% endhighlight %} | 282 {% endhighlight %} |
| 283 | 283 |
| 284 Then you will *only* import the names “foo” and “bar” from “somelib”. This is go
od if you are only using a small part of a library and want to make that clear.
Conversely: | 284 Then you will *only* import the names "foo" and "bar" from "somelib". This is go
od if you are only using a small part of a library and want to make that clear.
Conversely: |
| 285 | 285 |
| 286 {% highlight dart %} | 286 {% highlight dart %} |
| 287 #import('somelib.dart', hide: ['foo', 'bar']); | 287 #import('somelib.dart', hide: ['foo', 'bar']); |
| 288 {% endhighlight %} | 288 {% endhighlight %} |
| 289 | 289 |
| 290 Here, you import every name except “foo” and “bar”. This is good for excluding t
he one name that happens to cause a collision. | 290 Here, you import every name except "foo" and "bar". This is good for excluding t
he one name that happens to cause a collision. |
| 291 | 291 |
| 292 ([Tracking issue #817](http://dartbug.com/817)) | 292 ([Tracking issue #817](http://dartbug.com/817)) |
| 293 | 293 |
| 294 ## Re-export | 294 ## Re-export |
| 295 | 295 |
| 296 Let’s say you’re doing some refactoring and you decide to move a class from one
library to another. But, you don’t want to break all of the code that assumes th
at class is still in the old library. Ideally, you’d like code that imports *eit
her* of those to be able to get to your class: you want it to appear to be in bo
th places. | 296 Let’s say you’re doing some refactoring and you decide to move a class from one
library to another. But, you don’t want to break all of the code that assumes th
at class is still in the old library. Ideally, you’d like code that imports *eit
her* of those to be able to get to your class: you want it to appear to be in bo
th places. |
| 297 | 297 |
| 298 Or, let’s say you have a giant library with hundreds of names in it (we’ll call
it “dart:html”). You want to split that up into a few smaller libraries. But you
’d also like users that want the whole kit and caboodle to just be able to impor
t “dart:html” and get everything. | 298 Or, let’s say you have a giant library with hundreds of names in it (we’ll call
it "dart:html"). You want to split that up into a few smaller libraries. But you
’d also like users that want the whole kit and caboodle to just be able to impor
t "dart:html" and get everything. |
| 299 | 299 |
| 300 To fix this, Dart has “re-exports”. When you import a library, you can choose to
also re-export the names you import from it. That will make it appear to code u
sing *your* library that those names are coming directly from it. This lets you
decouple the library where users get something from the library where it’s physi
cally defined. For example: | 300 To fix this, Dart has "re-exports". When you import a library, you can choose to
also re-export the names you import from it. That will make it appear to code u
sing *your* library that those names are coming directly from it. This lets you
decouple the library where users get something from the library where it’s physi
cally defined. For example: |
| 301 | 301 |
| 302 {% highlight dart %} | 302 {% highlight dart %} |
| 303 // bar.dart | 303 // bar.dart |
| 304 someMethod() => print('hi!'); | 304 someMethod() => print('hi!'); |
| 305 anotherMethod() => print('hello!'); | 305 anotherMethod() => print('hello!'); |
| 306 | 306 |
| 307 // foo.dart | 307 // foo.dart |
| 308 #import('bar.dart', export: true); | 308 #import('bar.dart', export: true); |
| 309 {% endhighlight %} | 309 {% endhighlight %} |
| 310 | 310 |
| 311 Thanks to the `export: true` part here, any code that imports “foo.dart” will be
able to access `someMethod()` and `anotherMethod()` as if they had been defined
directly in “foo.dart”. You can use this in combination with selective imports
to only re-export a subset of the names that an imported library defines. If we
change the import in “foo.dart” to: | 311 Thanks to the `export: true` part here, any code that imports "foo.dart" will be
able to access `someMethod()` and `anotherMethod()` as if they had been defined
directly in "foo.dart". You can use this in combination with selective imports
to only re-export a subset of the names that an imported library defines. If we
change the import in "foo.dart" to: |
| 312 | 312 |
| 313 {% highlight dart %} | 313 {% highlight dart %} |
| 314 #import('bar.dart', show: ['someMethod'], export: true); | 314 #import('bar.dart', show: ['someMethod'], export: true); |
| 315 {% endhighlight %} | 315 {% endhighlight %} |
| 316 | 316 |
| 317 Then only `someMethod` will be re-exported. | 317 Then only `someMethod` will be re-exported. |
| 318 | 318 |
| 319 ([Tracking issue #760](http://dartbug.com/760)) | 319 ([Tracking issue #760](http://dartbug.com/760)) |
| 320 | 320 |
| 321 ## Static methods are constants | 321 ## Static methods are constants |
| (...skipping 13 matching lines...) Expand all Loading... |
| 335 const Logger(this.logCallback(arg)); | 335 const Logger(this.logCallback(arg)); |
| 336 } | 336 } |
| 337 {% endhighlight %} | 337 {% endhighlight %} |
| 338 | 338 |
| 339 ([Tracking issue #1652](http://dartbug.com/1652)) | 339 ([Tracking issue #1652](http://dartbug.com/1652)) |
| 340 | 340 |
| 341 ## New catch syntax | 341 ## New catch syntax |
| 342 | 342 |
| 343 One strange consequence of marrying Dart’s optional type semantics with a Java-l
ike syntax is that you end up with a syntax for `catch` clauses that *looks* lik
e a type annotation, but is very much not like a type annotation in Dart: Dart t
ype annotations have no runtime effects, but the type in a `catch` clause is use
d at runtime to test against the thrown exception. | 343 One strange consequence of marrying Dart’s optional type semantics with a Java-l
ike syntax is that you end up with a syntax for `catch` clauses that *looks* lik
e a type annotation, but is very much not like a type annotation in Dart: Dart t
ype annotations have no runtime effects, but the type in a `catch` clause is use
d at runtime to test against the thrown exception. |
| 344 | 344 |
| 345 This causes some confusion and some nasty syntactic corner cases. For example, i
f you just have `catch(foo)` does that mean “catch an exception of any type and
bind it to `foo`” (which lines up with other parameters in Dart where the type a
nnotation is optional), or does it mean “catch an exception of type `foo` and do
n’t bind it to a variable” (which is what it would mean in Java)? | 345 This causes some confusion and some nasty syntactic corner cases. For example, i
f you just have `catch(foo)` does that mean "catch an exception of any type and
bind it to `foo`" (which lines up with other parameters in Dart where the type a
nnotation is optional), or does it mean "catch an exception of type `foo` and do
n’t bind it to a variable" (which is what it would mean in Java)? |
| 346 | 346 |
| 347 To avoid that, we decided that that syntax is invalid and you *must* do either `
catch(var foo)` or `catch(foo someVar)` to be clear about your intent. But that’
s definitely *not* the syntax for a parameter in Dart, so now users trip over *t
hat.* | 347 To avoid that, we decided that that syntax is invalid and you *must* do either `
catch(var foo)` or `catch(foo someVar)` to be clear about your intent. But that’
s definitely *not* the syntax for a parameter in Dart, so now users trip over *t
hat.* |
| 348 | 348 |
| 349 Our fix is to not try to follow Java-style syntax for this at all. Instead, Dart
does: | 349 Our fix is to not try to follow Java-style syntax for this at all. Instead, Dart
does: |
| 350 | 350 |
| 351 {% highlight dart %} | 351 {% highlight dart %} |
| 352 try { | 352 try { |
| 353 ... | 353 ... |
| 354 } on SomeException catch(ex) { ... } | 354 } on SomeException catch(ex) { ... } |
| 355 {% endhighlight %} | 355 {% endhighlight %} |
| (...skipping 11 matching lines...) Expand all Loading... |
| 367 {% endhighlight %} | 367 {% endhighlight %} |
| 368 | 368 |
| 369 This makes the syntax for defining them closer to how they are invoked. (You ca
n of course have a curly block body too in addition to the simple lambda body sh
own above.) | 369 This makes the syntax for defining them closer to how they are invoked. (You ca
n of course have a curly block body too in addition to the simple lambda body sh
own above.) |
| 370 | 370 |
| 371 Setters now have an `=` after their name, before the parameter list: | 371 Setters now have an `=` after their name, before the parameter list: |
| 372 | 372 |
| 373 {% highlight dart %} | 373 {% highlight dart %} |
| 374 set theAnswer=(int value) { print('The answer is now $value.'); } | 374 set theAnswer=(int value) { print('The answer is now $value.'); } |
| 375 {% endhighlight %} | 375 {% endhighlight %} |
| 376 | 376 |
| 377 When reflecting over a type (in the forthcoming mirrors system), the name of a s
etter will include the “=”, so this makes the definition syntax reflect that. | 377 When reflecting over a type (in the forthcoming mirrors system), the name of a s
etter will include the "=", so this makes the definition syntax reflect that. |
| 378 | 378 |
| 379 ([Tracking issue #3602](http://dartbug.com/3602)) | 379 ([Tracking issue #3602](http://dartbug.com/3602)) |
| 380 | 380 |
| 381 ## Conclusion | 381 ## Conclusion |
| 382 | 382 |
| 383 There are a few other minor changes and clean-ups, but that’s the big noticeable
stuff. As always, your feedback, questions and comments are welcome on the [mai
ling list](http://dartlang.org/mailing-list) and our [issue tracker](http://dart
bug.com). | 383 There are a few other minor changes and clean-ups, but that’s the big noticeable
stuff. As always, your feedback, questions and comments are welcome on the [mai
ling list](http://dartlang.org/mailing-list) and our [issue tracker](http://dart
bug.com). |
| OLD | NEW |