|
9 | 9 |
|
10 | 10 | ## 2.17.0 |
11 | 11 |
|
| 12 | +### Language |
| 13 | + |
| 14 | +The following features are new in the Dart 2.17 [language version][]. To use |
| 15 | +them, you must set the lower bound on the SDK constraint for your package to |
| 16 | +2.17 or greater (`sdk: '>=2.17.0 <3.0.0'`). |
| 17 | + |
| 18 | +[language version]: https://dart.dev/guides/language/evolution |
| 19 | + |
| 20 | +- **[Enhanced enums with members][]**: Enum declarations can now define |
| 21 | + members including fields, constructors, methods, getters, etc. For example: |
| 22 | + |
| 23 | + ```dart |
| 24 | + enum Water { |
| 25 | + frozen(32), |
| 26 | + lukewarm(100), |
| 27 | + boiling(212); |
| 28 | +
|
| 29 | + final int tempInFahrenheit; |
| 30 | + const Water(this.tempInFahrenheit); |
| 31 | +
|
| 32 | + @override |
| 33 | + String toString() => "The $name water is $tempInFahrenheit F."; |
| 34 | + } |
| 35 | + ``` |
| 36 | +
|
| 37 | + Constructors must be `const` since enum values are always constants. If the |
| 38 | + constructor takes arguments, they are passed when the enum value is |
| 39 | + declared. |
| 40 | +
|
| 41 | + The above enum can be used like so: |
| 42 | +
|
| 43 | + ```dart |
| 44 | + void main() { |
| 45 | + print(Water.frozen); // prints "The frozen water is 32 F." |
| 46 | + } |
| 47 | + ``` |
| 48 | +
|
| 49 | +[enhanced enums with members]: https://github.com/dart-lang/language/blob/master/accepted/future-releases/enhanced-enums/feature-specification.md |
| 50 | +
|
| 51 | +- **[Super parameters][]**: When extending a class whose constructor takes |
| 52 | + parameters, the subclass constructor needs to provide arguments for them. |
| 53 | + Often, these are passed as parameters to the subclass constructor, which |
| 54 | + then forwards them to the superclass constructor. This is verbose because |
| 55 | + the subclass constructor must list the name and type of each parameter in |
| 56 | + its parameter list, and then explicitly forward each one as an argument to |
| 57 | + the superclass constructor. |
| 58 | +
|
| 59 | + [@roy-sianez][] suggested [allowing `super.`][super dot] before a subclass |
| 60 | + constructor parameter to implicitly forward it to the corresponding |
| 61 | + superclass constructor parameter. Applying this feature to Flutter |
| 62 | + eliminated [nearly 2,000 lines of code][flutter super]. For example, before: |
| 63 | +
|
| 64 | + ```dart |
| 65 | + class CupertinoPage<T> extends Page<T> { |
| 66 | + const CupertinoPage({ |
| 67 | + required this.child, |
| 68 | + this.maintainState = true, |
| 69 | + this.title, |
| 70 | + this.fullscreenDialog = false, |
| 71 | + LocalKey? key, |
| 72 | + String? name, |
| 73 | + Object? arguments, |
| 74 | + String? restorationId, |
| 75 | + }) : super( |
| 76 | + key: key, |
| 77 | + name: name, |
| 78 | + arguments: arguments, |
| 79 | + restorationId: restorationId, |
| 80 | + ); |
| 81 | +
|
| 82 | + // ... |
| 83 | + } |
| 84 | + ``` |
| 85 | +
|
| 86 | + And using super parameters: |
| 87 | +
|
| 88 | + ```dart |
| 89 | + class CupertinoPage<T> extends Page<T> { |
| 90 | + const CupertinoPage({ |
| 91 | + required this.child, |
| 92 | + this.maintainState = true, |
| 93 | + this.title, |
| 94 | + this.fullscreenDialog = false, |
| 95 | + super.key, |
| 96 | + super.name, |
| 97 | + super.arguments, |
| 98 | + super.restorationId, |
| 99 | + }); |
| 100 | +
|
| 101 | + // ... |
| 102 | + } |
| 103 | + ``` |
| 104 | +
|
| 105 | + From our analysis, over 90% of explicit superclass constructor calls can be |
| 106 | + completely eliminated, using `super.` parameters instead. |
| 107 | +
|
| 108 | +[super parameters]: https://github.com/dart-lang/language/blob/master/working/1855%20-%20super%20parameters/proposal.md |
| 109 | +[@roy-sianez]: https://github.com/roy-sianez |
| 110 | +[super dot]: https://github.com/dart-lang/language/issues/1855 |
| 111 | +[flutter super]: https://github.com/flutter/flutter/pull/100905/files |
| 112 | +
|
| 113 | +- **[Named args everywhere][]**: In a function call, Dart requires positional |
| 114 | + arguments to appear before named arguments. This can be frustrating for |
| 115 | + arguments like collection literals and function expressions that look best |
| 116 | + as the last argument in the argument list but are positional, like the |
| 117 | + `test()` function in the [test package][]: |
| 118 | +
|
| 119 | + ```dart |
| 120 | + main() { |
| 121 | + test('A test description', () { |
| 122 | + // Very long function body here... |
| 123 | + }, skip: true); |
| 124 | + } |
| 125 | + ``` |
| 126 | +
|
| 127 | + It would be better if the `skip` argument appeared at the top of the call |
| 128 | + to `test()` so that it wasn't easily overlooked, but since it's named and |
| 129 | + the test body argument is positional, `skip` must be placed at the end. |
| 130 | +
|
| 131 | + Dart 2.17 removes this restriction. Named arguments can be freely |
| 132 | + interleaved with positional arguments, allowing code like: |
| 133 | +
|
| 134 | + ```dart |
| 135 | + main() { |
| 136 | + test(skip: true, 'A test description', () { |
| 137 | + // Very long function body here... |
| 138 | + }); |
| 139 | + } |
| 140 | + ``` |
| 141 | +
|
| 142 | +[named args everywhere]: https://github.com/dart-lang/language/blob/master/accepted/future-releases/named-arguments-anywhere/feature-specification.md |
| 143 | +[test package]: https://pub.dev/packages/test |
| 144 | +
|
12 | 145 | ### Core libraries |
13 | 146 |
|
14 | 147 | #### `dart:core` |
@@ -275,6 +408,7 @@ in 2018, as it doesn't work with any Dart 2.x release. |
275 | 408 | - Pub now supports a separate `pubspec_overrides.yaml` file that can contain |
276 | 409 | `dependency_overrides`. This makes it easier to avoid checking the local |
277 | 410 | overrides into version control. |
| 411 | + |
278 | 412 | #### Linter |
279 | 413 |
|
280 | 414 | Updated the Linter to `1.18.0`, which includes changes that |
|
0 commit comments