sdk
sdk copied to clipboard
Dart 3 core library changes
Generally it's hard to evolve the Dart core libraries, as most changes tend to be potentially widely breaking. For example, adding a new member to a class in the core libraries can be breaking to any code that that implements that class, given all Dart classes are implicit interfaces.
While we still don't want major breaking changes in Dart 3 outside of the non-null discontinuation, we have an opportunity to be mildly breaking.
The concrete list of discussions is still under discussion.
dart:core
-
Add
Iterable.whereNotNull()
as an extension to Iterable indart:core
(currently inpackage:collection
as an extension) -
Add
Iterable.firstOrNull()
/Iterable.lastOrNull()
/Iterable.elementAtOrNull()
as extension methods to Iterable indart:core
(some currently inpackage:collection
as an extension) -
Add
DateTime.copyWith()
. Long standing request. As an extension method, to avoid breakage.
Maybe add a name
property to FileSystemEntity
and change the firstWhere()
method from Iterable
to return a nullable value...
With records being a thing, we may want to embrace them.
We have a number of "indexed" iterable extensions in package:collection
that would otherwise be worthy candidates for inclusion in dart:core
, but with records, we can instead introduce a single "add index to iterable" operation:
extension IterableExtension<T> on Iterable<T> {
Iterable<(int, T)> get indexed sync* {
var index = 0;
for (var element in this) yield (index++, element);
}
}
Then you would be able to do:
for (var (i, e) in something.indexed) {
print("#$i: $e");
}
(We'll be missing some affordances in the first release, for example we probably won't have patterns in parameters, so not everything will be as smooth as the for
-in
.)
We should consider whether there are other uses of records that afford a similar big result for a small effort.
Usually this one is mentioned as well:
extension MapExtension<K, V> on Map<K, V> {
Iterable<(K, V)> get keyed sync* {
for (var element in this.entries) yield (element.key, element.value);
}
}
// Example usage.
void main() {
var map = {1: "one", 2: "two"};
for (var (key, value) in map.keyed) {
print('$key: $value');
}
}
The Map.keyed
here is mostly redundant with the existing Iterable<MapEntry<K,V>> get entries
.
You can do for (var MapEntry(:key, :value) in map.entries) ...
with pattern matching. If we can get rid of the redundant MapEntry
too, it would be even better.
(It would be nice to make MapEntry
an alias for ({K key, V value})
, but that would break code currently using the constructor. I'm more inclined to make it either a struct
, or make it a view
on ({K key, V value})
, preferently a transparent view which can be cast in either direction, if such a thing exists. Really, I just want a place to hang the constructor.)
The DateTime.copyWith
extension is now merged:
https://dart-review.googlesource.com/c/sdk/+/258541
If I could ask for anything crazy in Dart 3, I would go with print("value is", a). I alwaaays struggle with Dart syntax, and it is possible to implement that without varargs. Since print is not supposed to run in release mode, the minimal performance impact is negligible.
https://github.com/dart-lang/sdk/issues/49084
Hey @lrhn can you please check the list at the top (which I updated) to see if it's complete for 3?
LGTM.