| Index: docs/newsletter/20170818.md
|
| diff --git a/docs/newsletter/20170818.md b/docs/newsletter/20170818.md
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..1db74634b551ea68600afa38ba2cdbbe5c2ca326
|
| --- /dev/null
|
| +++ b/docs/newsletter/20170818.md
|
| @@ -0,0 +1,214 @@
|
| +# Dart Language and Library Newsletter
|
| +2017-08-18
|
| +@floitschG
|
| +
|
| +Welcome to the Dart Language and Library Newsletter.
|
| +
|
| +## If you missed it
|
| +Did you know that you can write trailing commas to arguments and parameters? This feature was added to the specification about a year ago.
|
| +
|
| +It's main use-case is to unify parameter and argument lists that span multiple lines. For example, [Flutter] uses it extensively to keep tree-like instantiations nicely aligned:
|
| +
|
| +[Flutter]: http://flutter.io
|
| +
|
| +``` dart
|
| + return new Material(
|
| + // Column is a vertical, linear layout.
|
| + child: new Column(
|
| + children: <Widget>[
|
| + new MyAppBar(
|
| + title: new Text(
|
| + 'Example title',
|
| + style: Theme.of(context).primaryTextTheme.title,
|
| + ),
|
| + ),
|
| + new Expanded(
|
| + child: new Center(
|
| + child: new Text('Hello, world!'),
|
| + ),
|
| + ),
|
| + ],
|
| + ),
|
| +```
|
| +
|
| +Note how every argument list ends with a comma. The `dartfmt` tool knows about these trailing commas and ensures that the individual entries stay on their own lines so that it is easy to move them around with cut and paste.
|
| +
|
| +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.
|
| +
|
| +### Function Type Syntax
|
| +A few months ago, we added a new function type syntax to Dart (we mentioned it in our first newsletter).
|
| +
|
| +``` dart
|
| +// Examples:
|
| +typedef F = void Function(int); // A void function that takes an int.
|
| +
|
| +void foo(T Function<T>(T x) f) { // foo takes a generic function.
|
| + ...
|
| +}
|
| +
|
| +class A {
|
| + // A has a field `f` of type function that takes a String and returns void.
|
| + void Function(String) f;
|
| +}
|
| +```
|
| +
|
| +Before we added the new function-type syntaxes, we evaluated multiple options. In this section I will summarize some of the discussions we had.
|
| +
|
| +#### Motivation
|
| +The new function-type syntax intends to solve three issues:
|
| +
|
| +1. the old `typedef` syntax doesn't support generic types.
|
| +2. the old function syntax can't be used for fields and locals.
|
| +3. in the old syntax, providing only one identifier in an argument position is interpreted as name and not type. For example: `typedef f(int);` is *not* a typedef for a function that expects an `int`, but for a function that expects `dynamic` and names the argument "int".
|
| +
|
| +With Dart 2.0 we will support generic methods, and also generic closures. This means that a function can accept a generic function as argument. We were lacking a way to express this type.
|
| +
|
| +Dart 1.x has two ways to express function types: a) an inline syntax for parameters and b) `typedef`s.
|
| +
|
| +It was easy to extend the inline syntax to support generic arguments:
|
| +
|
| +
|
| +``` dart
|
| +// Takes a function `factoryForA` that is generic on T.
|
| +void foo(A<T> factoryForA<T>()) {
|
| + A<int> x = factoryForA<int>();
|
| + A<String> x = factoryForA<String>();
|
| +}
|
| +```
|
| +
|
| +However, there was no easy way to do the same for `typedef`s:
|
| +
|
| +``` dart
|
| +typedef A<T> FactoryForA<T>();// Does *not* do what we want it to do:
|
| +
|
| +FactoryForA f; // A function that returns an `A<dynamic>`.
|
| +FactoryForA<String> f2; // A function that returns an `A<String>`.
|
| +f<int>(); // Error: `f` is not generic.
|
| +```
|
| +
|
| +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 could change it as follows:
|
| +
|
| +``` dart
|
| +typedef<T> List<T> TemplateTypedef();
|
| +TemplateTypedef<int> f; // A function that returns a List<int>.
|
| +TemplateTypedef f; // A function that returns a List<dynamic>.
|
| +
|
| +typedef List<T> GenericTypedef<T>();
|
| +GenericTypedef f; // A function that is generic.
|
| +List<int> ints = f<int>();
|
| +List<String> strings = f<String>();
|
| +```
|
| +
|
| +Given that this would be a breaking change we explored alternatives that would also solve the other two issues. In particular the new syntax had to work for locals and fields, too.
|
| +
|
| +First and foremost the new syntax had to be readable. It also had to solve the three mentioned issues. Finally, we wanted to make sure, we didn't choose a syntax that would hinder future evolution of the language. We made sure that the syntax would work with:
|
| +- nullability: the syntax must be nullable without too much hassle:
|
| + ``` dart
|
| + (int)->int?; // A function that is nullable, or that returns a nullable integer?
|
| + Problem disappears with <-
|
| + int <- (int)? ; vs int? <- (int)
|
| + ```
|
| +- union types (in case we ever want them).
|
| +
|
| +
|
| +#### Common Characteristics
|
| +For all the following proposals we had decided that the arguments could either be just the type, or optionally have a name. For example, `(int)->int` is equivalent to `(int id)->int`. Especially with multiple arguments of the same type, providing a name can make it much easier to reason about the type: `(int id, int priority) -> void`. However, type-wise these parameter names are ignored.
|
| +
|
| +All of the proposals thus interpret single-argument identifiers as types. This is in contrast to the old syntax where a single identifier would state the name of the parameter: in `void foo(bar(int)) {...}` the `int` is the name of the parameter to `bar`. This discrepancy is hopefully temporary, as we intend to eventually change the behavior of the old syntax.
|
| +
|
| +##### Right -> Arrow
|
| +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 =>).
|
| +
|
| +Examples:
|
| +``` dart
|
| +typedef F = (int) -> void; // Function from (int) to void.
|
| +typedef F<T> = () -> List<T>; // Template Typedef.
|
| +typedef F = <T>(T) -> List<T>; // Generic function from T to List<T>.
|
| +```
|
| +
|
| +We could even allow a short form when there is only one argument: `int->int`.
|
| +
|
| +We have experimented with this syntax: [https://codereview.chromium.org/2439573003/]
|
| +
|
| +Advantages:
|
| +- easy to learn and familiar to many developers.
|
| +- could support shorthand form `int->int`.
|
| +
|
| +Open questions:
|
| +- support shorthand form?
|
| +- whitespace. Should it be `(int, int) -> String` or `(int, int)->String`, etc.
|
| +
|
| +Disadvantages:
|
| +- Relatively late token. The parser would have to do relatively big lookaheads.
|
| +- Works badly with nullable types:
|
| + ``` dart
|
| + typedef F = (int) -> int?; // Nullable function or nullable int?
|
| + // Could be disambiguated as follows:
|
| + typedef F = ((int)->int)?; // Clearly nullable function.
|
| + ```
|
| +
|
| +
|
| +##### Left <- Arrow
|
| +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).
|
| +
|
| +Examples:
|
| +``` dart
|
| +typedef F = void <- (int); // Function from (int) to void.
|
| +typedef F<T> = List<T> <- (); // Template Typedef.
|
| +typedef F = List<T> <- <T>(T); // Generic function from T to List<T>.
|
| +```
|
| +
|
| +Could also allow a short form: `int<-int`. (For some reason this seems to read less nicely than `int->int`.)
|
| +
|
| +We have experimented with this syntax: [https://codereview.chromium.org/2466393002/]
|
| +
|
| +Advantages:
|
| +- 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 first line.
|
| +- faster to parse, since the `<-` doesn't require a lot of look-ahead.
|
| +- relatively similar to `->`.
|
| +- no problems with nullable types:
|
| + ``` dart
|
| + typedef F = int <- (int)?; // Nullable function.
|
| + typedef F = int? <- (int); // Returns nullable int.
|
| + ```
|
| +
|
| +Open Questions:
|
| +- whitespace?
|
| +- support shorthand form?
|
| +
|
| +Disadvantages:
|
| +- `<-` is ambiguous: `x<-y ? foo(x) : foo(y) // if x < (-y) ...`.
|
| +- Not as familiar as `->`.
|
| +
|
| +##### Function
|
| +Dart already uses `Function` as general type for functions. It is relatively straightforward to extend the use of `Function` to include return and parameter types. (And no: it's not `Function<int, int>` since that wouldn't work for named arguments).
|
| +
|
| +
|
| +``` dart
|
| +typedef F = void Function(int); // Function from (int) to void.
|
| +typedef F<T> = List<T> Function(); // Template Typedef.
|
| +typedef F = List<T> Function<T>(T); // Generic function from T to List<T>.
|
| +```
|
| +
|
| +This form does not allow any shorthand syntax, but fits nicely into the existing parameter syntax.
|
| +
|
| +Before we accepted this syntax, we had experimented with this syntax: [https://codereview.chromium.org/2482923002/]
|
| +
|
| +Advantages:
|
| +- very similar to the syntax of the corresponding function declarations.
|
| +- no ambiguity.
|
| +- (almost) no new syntax. That is, the type can be immediately extrapolated from other syntax.
|
| +- no open questions wrt whitespace.
|
| +- symmetries with existing use of `Function`:
|
| + ``` dart
|
| + Function f; // a function.
|
| + Function(int x) f; // a function that takes an int.
|
| + double Function(int) f; // a function that takes an int and returns a double.
|
| + ```
|
| +
|
| +Disadvantages:
|
| +- longer.
|
| +
|
| +##### Conclusion
|
| +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.
|
| +
|
|
|