| 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. [No explicit interfaces](#no-explicit-interfaces) | 15 1. [No explicit interfaces](#no-explicit-interfaces) |
| 16 1. [No "+" on String](#no--on-string) | 16 1. [No "+" on String](#no--on-string) |
| 17 1. [No throwing `null`](#no-throwing-null) | 17 1. [No throwing `null`](#no-throwing-null) |
| 18 1. [The “as” cast operator](#the-as-cast-operator) | 18 1. [The "as" cast operator](#the-as-cast-operator) |
| 19 1. [Cascades](#cascades) | 19 1. [Cascades](#cascades) |
| 20 1. [Lazy static initialization](#lazy-static-initialization) | 20 1. [Lazy static initialization](#lazy-static-initialization) |
| 21 1. [Support “const” modifier for variables](#support-const-modifier-for-variable
s) | 21 1. [Support "const" modifier for variables](#support-const-modifier-for-variable
s) |
| 22 1. [Syntax for defining operators](#syntax-for-defining-operators) | 22 1. [Syntax for defining operators](#syntax-for-defining-operators) |
| 23 1. [Split library scope and import scope](#split-library-scope-and-import-scope) | 23 1. [Split library scope and import scope](#split-library-scope-and-import-scope) |
| 24 1. [Revised switch](#revised-switch) | 24 1. [Revised switch](#revised-switch) |
| 25 1. [Selective imports](#selective-imports) | 25 1. [Selective imports](#selective-imports) |
| 26 1. [Re-export](#re-export) | 26 1. [Re-export](#re-export) |
| 27 1. [Static methods are constants](#static-methods-are-constants) | 27 1. [Static methods are constants](#static-methods-are-constants) |
| 28 1. [New catch syntax](#new-catch-syntax) | 28 1. [New catch syntax](#new-catch-syntax) |
| 29 1. [Getter and setter definition syntax](#getter-and-setter-definition-syntax) | 29 1. [Getter and setter definition syntax](#getter-and-setter-definition-syntax) |
| 30 1. [Conclusion](#conclusion) | 30 1. [Conclusion](#conclusion) |
| 31 {:.toc} | 31 {:.toc} |
| (...skipping 25 matching lines...) Expand all Loading... |
| 57 {% endhighlight %} | 57 {% endhighlight %} |
| 58 | 58 |
| 59 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. | 59 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. |
| 60 | 60 |
| 61 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. | 61 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. |
| 62 | 62 |
| 63 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
. | 63 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
. |
| 64 | 64 |
| 65 ## No "+" on String | 65 ## No "+" on String |
| 66 | 66 |
| 67 A deeply contentious issue, Dart no longer allows using the “+” operator on stri
ngs. So no more: | 67 A deeply contentious issue, Dart no longer allows using the "+" operator on stri
ngs. So no more: |
| 68 | 68 |
| 69 {% highlight dart %} | 69 {% highlight dart %} |
| 70 print("Hi, " + yourName); | 70 print("Hi, " + yourName); |
| 71 {% endhighlight %} | 71 {% endhighlight %} |
| 72 | 72 |
| 73 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: | 73 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: |
| 74 | 74 |
| 75 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. | 75 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. |
| 76 | 76 |
| 77 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. | 77 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. |
| 78 | 78 |
| 79 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). | 79 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). |
| 80 | 80 |
| 81 ([Tracking issue #3707](http://dartbug.com/3707)) | 81 ([Tracking issue #3707](http://dartbug.com/3707)) |
| 82 | 82 |
| 83 ## No throwing `null` | 83 ## No throwing `null` |
| 84 | 84 |
| 85 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. | 85 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. |
| 86 | 86 |
| 87 *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. | 87 *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. |
| 88 | 88 |
| 89 ([Tracking issue #2940](http://dartbug.com/2940)) | 89 ([Tracking issue #2940](http://dartbug.com/2940)) |
| 90 | 90 |
| 91 ## The “as” cast operator | 91 ## The "as" cast operator |
| 92 | 92 |
| 93 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: | 93 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: |
| 94 | 94 |
| 95 {% highlight dart %} | 95 {% highlight dart %} |
| 96 ButtonElement button = query('button'); | 96 ButtonElement button = query('button'); |
| 97 button.value = 1234; | 97 button.value = 1234; |
| 98 {% endhighlight %} | 98 {% endhighlight %} |
| 99 | 99 |
| 100 Now you can do: | 100 Now you can do: |
| 101 | 101 |
| (...skipping 19 matching lines...) Expand all Loading... |
| 121 | 121 |
| 122 or the tedium of having to define a local variable: | 122 or the tedium of having to define a local variable: |
| 123 | 123 |
| 124 {% highlight dart %} | 124 {% highlight dart %} |
| 125 var toggleButton = query('#my-form').query('button'); | 125 var toggleButton = query('#my-form').query('button'); |
| 126 toggleButton.classes.add('toggle'); | 126 toggleButton.classes.add('toggle'); |
| 127 toggleButton.text = 'Click Me!'; | 127 toggleButton.text = 'Click Me!'; |
| 128 toggleButton.labels.add(toggleLabel); | 128 toggleButton.labels.add(toggleLabel); |
| 129 {% endhighlight %} | 129 {% endhighlight %} |
| 130 | 130 |
| 131 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. | 131 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. |
| 132 | 132 |
| 133 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: | 133 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: |
| 134 | 134 |
| 135 {% highlight dart %} | 135 {% highlight dart %} |
| 136 query('#my-form').query('button') | 136 query('#my-form').query('button') |
| 137 ..classes.add('toggle') | 137 ..classes.add('toggle') |
| 138 ..text = 'Click Me!' | 138 ..text = 'Click Me!' |
| 139 ..labels.add(toggleLabel); | 139 ..labels.add(toggleLabel); |
| 140 {% endhighlight %} | 140 {% endhighlight %} |
| 141 | 141 |
| 142 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. | 142 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. |
| 143 | 143 |
| 144 ([Tracking issue #2501](http://dartbug.com/2501)) | 144 ([Tracking issue #2501](http://dartbug.com/2501)) |
| 145 | 145 |
| 146 ## Lazy static initialization | 146 ## Lazy static initialization |
| 147 | 147 |
| 148 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: | 148 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: |
| 149 | 149 |
| 150 {% highlight dart %} | 150 {% highlight dart %} |
| 151 class Stopwatch { | 151 class Stopwatch { |
| 152 static final startTime = new DateTime.now(); | 152 static final startTime = new DateTime.now(); |
| 153 } | 153 } |
| 154 {% endhighlight %} | 154 {% endhighlight %} |
| 155 | 155 |
| 156 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. | 156 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. |
| 157 | 157 |
| 158 ([Tracking issue #3557](http://dartbug.com/3557)) | 158 ([Tracking issue #3557](http://dartbug.com/3557)) |
| 159 | 159 |
| 160 ## Support “const” modifier for variables | 160 ## Support "const" modifier for variables |
| 161 | 161 |
| 162 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: | 162 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: |
| 163 | 163 |
| 164 {% highlight dart %} | 164 {% highlight dart %} |
| 165 class SomeClass { | 165 class SomeClass { |
| 166 static final someConstant = 123; | 166 static final someConstant = 123; |
| 167 static final aConstList = const [someConstant]; | 167 static final aConstList = const [someConstant]; |
| 168 } | 168 } |
| 169 {% endhighlight %} | 169 {% endhighlight %} |
| 170 | 170 |
| 171 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: | 171 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: |
| 172 | 172 |
| 173 {% highlight dart %} | 173 {% highlight dart %} |
| 174 class SomeClass { | 174 class SomeClass { |
| 175 static const someConstant = 123; // OK | 175 static const someConstant = 123; // OK |
| 176 static final startTime = new DateTime.now(); // OK too | 176 static final startTime = new DateTime.now(); // OK too |
| 177 static const aConstList = const [someConstant]; // also OK | 177 static const aConstList = const [someConstant]; // also OK |
| 178 } | 178 } |
| 179 {% endhighlight %} | 179 {% endhighlight %} |
| 180 | 180 |
| 181 ([Tracking issue #3549](http://dartbug.com/3549)) | 181 ([Tracking issue #3549](http://dartbug.com/3549)) |
| 182 | 182 |
| 183 ## Syntax for defining operators | 183 ## Syntax for defining operators |
| 184 | 184 |
| 185 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). | 185 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). |
| 186 | 186 |
| 187 {% highlight dart %} | 187 {% highlight dart %} |
| 188 class MagicNumber { | 188 class MagicNumber { |
| 189 bool operator ==(other) => … | 189 bool operator ==(other) => … |
| 190 MagicNumber operator -() => … // unary negate | 190 MagicNumber operator -() => … // unary negate |
| 191 MagicNumber operator -(other) => … // infix minus | 191 MagicNumber operator -(other) => … // infix minus |
| 192 } | 192 } |
| 193 {% endhighlight %} | 193 {% endhighlight %} |
| 194 | 194 |
| 195 ([Tracking issue #3765](http://dartbug.com/3765)) | 195 ([Tracking issue #3765](http://dartbug.com/3765)) |
| 196 | 196 |
| 197 ## Split library scope and import scope | 197 ## Split library scope and import scope |
| 198 | 198 |
| 199 Stephen [explains the rationale for this change](http://code.google.com/p/dart/i
ssues/detail?id=1285) better than I can: | 199 Stephen [explains the rationale for this change](http://code.google.com/p/dart/i
ssues/detail?id=1285) better than I can: |
| 200 | 200 |
| 201 > 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. | 201 > 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. |
| 202 | 202 |
| 203 What he means here is consider you have this program: | 203 What he means here is consider you have this program: |
| 204 | 204 |
| 205 {% highlight dart %} | 205 {% highlight dart %} |
| 206 #import('somelib.dart'); | 206 #import('somelib.dart'); |
| 207 | 207 |
| 208 foo() => print('foo!'); | 208 foo() => print('foo!'); |
| 209 main() => foo(); | 209 main() => foo(); |
| 210 {% endhighlight %} | 210 {% endhighlight %} |
| 211 | 211 |
| 212 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: | 212 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: |
| 213 | 213 |
| 214 > 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. | 214 > 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. |
| 215 | 215 |
| 216 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. | 216 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. |
| 217 | 217 |
| 218 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. | 218 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. |
| 219 | 219 |
| 220 ([Tracking issue #1285](http://dartbug.com/1285)) | 220 ([Tracking issue #1285](http://dartbug.com/1285)) |
| 221 | 221 |
| 222 ## Revised switch | 222 ## Revised switch |
| 223 | 223 |
| 224 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: | 224 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: |
| 225 | 225 |
| 226 {% highlight dart %} | 226 {% highlight dart %} |
| (...skipping 14 matching lines...) Expand all Loading... |
| 241 hasBeard = true; | 241 hasBeard = true; |
| 242 } else { | 242 } else { |
| 243 hasBeard = false; | 243 hasBeard = false; |
| 244 } | 244 } |
| 245 {% endhighlight %} | 245 {% endhighlight %} |
| 246 | 246 |
| 247 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. | 247 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. |
| 248 | 248 |
| 249 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)`. | 249 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)`. |
| 250 | 250 |
| 251 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. | 251 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. |
| 252 | 252 |
| 253 ## Selective imports | 253 ## Selective imports |
| 254 | 254 |
| 255 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. | 255 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. |
| 256 | 256 |
| 257 Now, you’ll be given finer grained control. If you do: | 257 Now, you’ll be given finer grained control. If you do: |
| 258 | 258 |
| 259 {% highlight dart %} | 259 {% highlight dart %} |
| 260 #import('somelib.dart', show: ['foo', 'bar']); | 260 #import('somelib.dart', show: ['foo', 'bar']); |
| 261 {% endhighlight %} | 261 {% endhighlight %} |
| 262 | 262 |
| 263 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: | 263 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: |
| 264 | 264 |
| 265 {% highlight dart %} | 265 {% highlight dart %} |
| 266 #import('somelib.dart', hide: ['foo', 'bar']); | 266 #import('somelib.dart', hide: ['foo', 'bar']); |
| 267 {% endhighlight %} | 267 {% endhighlight %} |
| 268 | 268 |
| 269 Here, you import every name except “foo” and “bar”. This is good for excluding t
he one name that happens to cause a collision. | 269 Here, you import every name except "foo" and "bar". This is good for excluding t
he one name that happens to cause a collision. |
| 270 | 270 |
| 271 ([Tracking issue #817](http://dartbug.com/817)) | 271 ([Tracking issue #817](http://dartbug.com/817)) |
| 272 | 272 |
| 273 ## Re-export | 273 ## Re-export |
| 274 | 274 |
| 275 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. | 275 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. |
| 276 | 276 |
| 277 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. | 277 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. |
| 278 | 278 |
| 279 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: | 279 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: |
| 280 | 280 |
| 281 {% highlight dart %} | 281 {% highlight dart %} |
| 282 // bar.dart | 282 // bar.dart |
| 283 someMethod() => print('hi!'); | 283 someMethod() => print('hi!'); |
| 284 anotherMethod() => print('hello!'); | 284 anotherMethod() => print('hello!'); |
| 285 | 285 |
| 286 // foo.dart | 286 // foo.dart |
| 287 #import('bar.dart', export: true); | 287 #import('bar.dart', export: true); |
| 288 {% endhighlight %} | 288 {% endhighlight %} |
| 289 | 289 |
| 290 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: | 290 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: |
| 291 | 291 |
| 292 {% highlight dart %} | 292 {% highlight dart %} |
| 293 #import('bar.dart', show: ['someMethod'], export: true); | 293 #import('bar.dart', show: ['someMethod'], export: true); |
| 294 {% endhighlight %} | 294 {% endhighlight %} |
| 295 | 295 |
| 296 Then only `someMethod` will be re-exported. | 296 Then only `someMethod` will be re-exported. |
| 297 | 297 |
| 298 ([Tracking issue #760](http://dartbug.com/760)) | 298 ([Tracking issue #760](http://dartbug.com/760)) |
| 299 | 299 |
| 300 ## Static methods are constants | 300 ## Static methods are constants |
| (...skipping 13 matching lines...) Expand all Loading... |
| 314 const Logger(this.logCallback(arg)); | 314 const Logger(this.logCallback(arg)); |
| 315 } | 315 } |
| 316 {% endhighlight %} | 316 {% endhighlight %} |
| 317 | 317 |
| 318 ([Tracking issue #1652](http://dartbug.com/1652)) | 318 ([Tracking issue #1652](http://dartbug.com/1652)) |
| 319 | 319 |
| 320 ## New catch syntax | 320 ## New catch syntax |
| 321 | 321 |
| 322 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. | 322 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. |
| 323 | 323 |
| 324 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)? | 324 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)? |
| 325 | 325 |
| 326 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.* | 326 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.* |
| 327 | 327 |
| 328 Our fix is to not try to follow Java-style syntax for this at all. Instead, Dart
does: | 328 Our fix is to not try to follow Java-style syntax for this at all. Instead, Dart
does: |
| 329 | 329 |
| 330 {% highlight dart %} | 330 {% highlight dart %} |
| 331 try { | 331 try { |
| 332 ... | 332 ... |
| 333 } on SomeException catch(ex) { ... } | 333 } on SomeException catch(ex) { ... } |
| 334 {% endhighlight %} | 334 {% endhighlight %} |
| (...skipping 11 matching lines...) Expand all Loading... |
| 346 {% endhighlight %} | 346 {% endhighlight %} |
| 347 | 347 |
| 348 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.) | 348 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.) |
| 349 | 349 |
| 350 Setters now have an `=` after their name, before the parameter list: | 350 Setters now have an `=` after their name, before the parameter list: |
| 351 | 351 |
| 352 {% highlight dart %} | 352 {% highlight dart %} |
| 353 set theAnswer=(int value) { print('The answer is now $value.'); } | 353 set theAnswer=(int value) { print('The answer is now $value.'); } |
| 354 {% endhighlight %} | 354 {% endhighlight %} |
| 355 | 355 |
| 356 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. | 356 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. |
| 357 | 357 |
| 358 ([Tracking issue #3602](http://dartbug.com/3602)) | 358 ([Tracking issue #3602](http://dartbug.com/3602)) |
| 359 | 359 |
| 360 ## Conclusion | 360 ## Conclusion |
| 361 | 361 |
| 362 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). | 362 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 |