OLD | NEW |
(Empty) | |
| 1 # Dart Language and Library Newsletter |
| 2 2017-08-18 |
| 3 @floitschG |
| 4 |
| 5 Welcome to the Dart Language and Library Newsletter. |
| 6 |
| 7 ## If you missed it |
| 8 Did you know that you can write trailing commas to arguments and parameters? Thi
s feature was added to the specification about a year ago. |
| 9 |
| 10 It's main use-case is to unify parameter and argument lists that span multiple l
ines. For example, [Flutter] uses it extensively to keep tree-like instantiation
s nicely aligned: |
| 11 |
| 12 [Flutter]: http://flutter.io |
| 13 |
| 14 ``` dart |
| 15 return new Material( |
| 16 // Column is a vertical, linear layout. |
| 17 child: new Column( |
| 18 children: <Widget>[ |
| 19 new MyAppBar( |
| 20 title: new Text( |
| 21 'Example title', |
| 22 style: Theme.of(context).primaryTextTheme.title, |
| 23 ), |
| 24 ), |
| 25 new Expanded( |
| 26 child: new Center( |
| 27 child: new Text('Hello, world!'), |
| 28 ), |
| 29 ), |
| 30 ], |
| 31 ), |
| 32 ``` |
| 33 |
| 34 Note how every argument list ends with a comma. The `dartfmt` tool knows about t
hese trailing commas and ensures that the individual entries stay on their own l
ines so that it is easy to move them around with cut and paste. |
| 35 |
| 36 Recently, we also updated the specification to allow trailing commas in `assert`
s. This makes the syntax of `assert`s more consistent with function calls. |
| 37 |
| 38 ### Function Type Syntax |
| 39 A few months ago, we added a new function type syntax to Dart (we mentioned it i
n our first newsletter). |
| 40 |
| 41 ``` dart |
| 42 // Examples: |
| 43 typedef F = void Function(int); // A void function that takes an int. |
| 44 |
| 45 void foo(T Function<T>(T x) f) { // foo takes a generic function. |
| 46 ... |
| 47 } |
| 48 |
| 49 class A { |
| 50 // A has a field `f` of type function that takes a String and returns void. |
| 51 void Function(String) f; |
| 52 } |
| 53 ``` |
| 54 |
| 55 Before we added the new function-type syntaxes, we evaluated multiple options. I
n this section I will summarize some of the discussions we had. |
| 56 |
| 57 #### Motivation |
| 58 The new function-type syntax intends to solve three issues: |
| 59 |
| 60 1. the old `typedef` syntax doesn't support generic types. |
| 61 2. the old function syntax can't be used for fields and locals. |
| 62 3. in the old syntax, providing only one identifier in an argument position is i
nterpreted as name and not type. For example: `typedef f(int);` is *not* a type
def for a function that expects an `int`, but for a function that expects `dynam
ic` and names the argument "int". |
| 63 |
| 64 With Dart 2.0 we will support generic methods, and also generic closures. This m
eans that a function can accept a generic function as argument. We were lacking
a way to express this type. |
| 65 |
| 66 Dart 1.x has two ways to express function types: a) an inline syntax for paramet
ers and b) `typedef`s. |
| 67 |
| 68 It was easy to extend the inline syntax to support generic arguments: |
| 69 |
| 70 |
| 71 ``` dart |
| 72 // Takes a function `factoryForA` that is generic on T. |
| 73 void foo(A<T> factoryForA<T>()) { |
| 74 A<int> x = factoryForA<int>(); |
| 75 A<String> x = factoryForA<String>(); |
| 76 } |
| 77 ``` |
| 78 |
| 79 However, there was no easy way to do the same for `typedef`s: |
| 80 |
| 81 ``` dart |
| 82 typedef A<T> FactoryForA<T>();// Does *not* do what we want it to do: |
| 83 |
| 84 FactoryForA f; // A function that returns an `A<dynamic>`. |
| 85 FactoryForA<String> f2; // A function that returns an `A<String>`. |
| 86 f<int>(); // Error: `f` is not generic. |
| 87 ``` |
| 88 |
| 89 We had already used the most consistent place for the generic method argument as
a template argument to the `typedef` itself. If we could go back in time, we co
uld change it as follows: |
| 90 |
| 91 ``` dart |
| 92 typedef<T> List<T> TemplateTypedef(); |
| 93 TemplateTypedef<int> f; // A function that returns a List<int>. |
| 94 TemplateTypedef f; // A function that returns a List<dynamic>. |
| 95 |
| 96 typedef List<T> GenericTypedef<T>(); |
| 97 GenericTypedef f; // A function that is generic. |
| 98 List<int> ints = f<int>(); |
| 99 List<String> strings = f<String>(); |
| 100 ``` |
| 101 |
| 102 Given that this would be a breaking change we explored alternatives that would a
lso solve the other two issues. In particular the new syntax had to work for loc
als and fields, too. |
| 103 |
| 104 First and foremost the new syntax had to be readable. It also had to solve the t
hree mentioned issues. Finally, we wanted to make sure, we didn't choose a synta
x that would hinder future evolution of the language. We made sure that the synt
ax would work with: |
| 105 - nullability: the syntax must be nullable without too much hassle: |
| 106 ``` dart |
| 107 (int)->int?; // A function that is nullable, or that returns a nullable inte
ger? |
| 108 Problem disappears with <- |
| 109 int <- (int)? ; vs int? <- (int) |
| 110 ``` |
| 111 - union types (in case we ever want them). |
| 112 |
| 113 |
| 114 #### Common Characteristics |
| 115 For all the following proposals we had decided that the arguments could either b
e just the type, or optionally have a name. For example, `(int)->int` is equival
ent to `(int id)->int`. Especially with multiple arguments of the same type, pro
viding a name can make it much easier to reason about the type: `(int id, int pr
iority) -> void`. However, type-wise these parameter names are ignored. |
| 116 |
| 117 All of the proposals thus interpret single-argument identifiers as types. This i
s in contrast to the old syntax where a single identifier would state the name o
f the parameter: in `void foo(bar(int)) {...}` the `int` is the name of the para
meter to `bar`. This discrepancy is hopefully temporary, as we intend to eventua
lly change the behavior of the old syntax. |
| 118 |
| 119 ##### Right -> Arrow |
| 120 Using `->` as function-type syntax feels very natural and is used in many other
languages: Swift, F#, SML, OCaml, Haskell, Miranda, Coq, Kotlin, and Scala (with
=>). |
| 121 |
| 122 Examples: |
| 123 ``` dart |
| 124 typedef F = (int) -> void; // Function from (int) to void. |
| 125 typedef F<T> = () -> List<T>; // Template Typedef. |
| 126 typedef F = <T>(T) -> List<T>; // Generic function from T to List<T>. |
| 127 ``` |
| 128 |
| 129 We could even allow a short form when there is only one argument: `int->int`. |
| 130 |
| 131 We have experimented with this syntax: [https://codereview.chromium.org/24395730
03/] |
| 132 |
| 133 Advantages: |
| 134 - easy to learn and familiar to many developers. |
| 135 - could support shorthand form `int->int`. |
| 136 |
| 137 Open questions: |
| 138 - support shorthand form? |
| 139 - whitespace. Should it be `(int, int) -> String` or `(int, int)->String`, etc. |
| 140 |
| 141 Disadvantages: |
| 142 - Relatively late token. The parser would have to do relatively big lookaheads. |
| 143 - Works badly with nullable types: |
| 144 ``` dart |
| 145 typedef F = (int) -> int?; // Nullable function or nullable int? |
| 146 // Could be disambiguated as follows: |
| 147 typedef F = ((int)->int)?; // Clearly nullable function. |
| 148 ``` |
| 149 |
| 150 |
| 151 ##### Left <- Arrow |
| 152 This section explores using `<-` as function-type syntax. There is at least one
other language that uses this syntax: [Twelf](http://www.cs.cmu.edu/~twelf/guide
-1-2/twelf_3.html). |
| 153 |
| 154 Examples: |
| 155 ``` dart |
| 156 typedef F = void <- (int); // Function from (int) to void. |
| 157 typedef F<T> = List<T> <- (); // Template Typedef. |
| 158 typedef F = List<T> <- <T>(T); // Generic function from T to List<T>. |
| 159 ``` |
| 160 |
| 161 Could also allow a short form: `int<-int`. (For some reason this seems to read
less nicely than `int->int`.) |
| 162 |
| 163 We have experimented with this syntax: [https://codereview.chromium.org/24663930
02/] |
| 164 |
| 165 Advantages: |
| 166 - return value is on the left, similar to normal function signatures. This also
simplifies `typedef`s, where the return value is more likely to stay on the firs
t line. |
| 167 - faster to parse, since the `<-` doesn't require a lot of look-ahead. |
| 168 - relatively similar to `->`. |
| 169 - no problems with nullable types: |
| 170 ``` dart |
| 171 typedef F = int <- (int)?; // Nullable function. |
| 172 typedef F = int? <- (int); // Returns nullable int. |
| 173 ``` |
| 174 |
| 175 Open Questions: |
| 176 - whitespace? |
| 177 - support shorthand form? |
| 178 |
| 179 Disadvantages: |
| 180 - `<-` is ambiguous: `x<-y ? foo(x) : foo(y) // if x < (-y) ...`. |
| 181 - Not as familiar as `->`. |
| 182 |
| 183 ##### Function |
| 184 Dart already uses `Function` as general type for functions. It is relatively str
aightforward to extend the use of `Function` to include return and parameter typ
es. (And no: it's not `Function<int, int>` since that wouldn't work for named ar
guments). |
| 185 |
| 186 |
| 187 ``` dart |
| 188 typedef F = void Function(int); // Function from (int) to void. |
| 189 typedef F<T> = List<T> Function(); // Template Typedef. |
| 190 typedef F = List<T> Function<T>(T); // Generic function from T to List<T>. |
| 191 ``` |
| 192 |
| 193 This form does not allow any shorthand syntax, but fits nicely into the existing
parameter syntax. |
| 194 |
| 195 Before we accepted this syntax, we had experimented with this syntax: [https://c
odereview.chromium.org/2482923002/] |
| 196 |
| 197 Advantages: |
| 198 - very similar to the syntax of the corresponding function declarations. |
| 199 - no ambiguity. |
| 200 - (almost) no new syntax. That is, the type can be immediately extrapolated from
other syntax. |
| 201 - no open questions wrt whitespace. |
| 202 - symmetries with existing use of `Function`: |
| 203 ``` dart |
| 204 Function f; // a function. |
| 205 Function(int x) f; // a function that takes an int. |
| 206 double Function(int) f; // a function that takes an int and returns a double. |
| 207 ``` |
| 208 |
| 209 Disadvantages: |
| 210 - longer. |
| 211 |
| 212 ##### Conclusion |
| 213 We found that the `Function`-based syntax fits nicely into Dart and fulfills all
of our requirements. Due to its similarity to function declarations it is also
very future-proof. Any feature that works with function declarations should work
with the `Function`-type syntax, as well. |
| 214 |
OLD | NEW |