Dart list literals have spreads and iteration, which makes some things possible in an iterable which would otherwise require a specialized constructor call. For example List.filled(42, "") can be written as [for (var i = 0; i < 42; i++) ""].
That's still not very concise, though.
With non-nullable types, initializing a list to a all the same value becomes more common, so what if we had a more concise way t o do the above: ["" x 42].
This is a special element-entry syntax which only works in list literals (because it makes no sense to repeat elements in a set or map).
It treats a single x (that's a lower-case X letter) as an infix operator, where the second operand must be an integer, and the first operand must be an expression (or, potentially, a list element).
PROs:
["" x 42] or [0, 1 x count, 0].[(...otherList) x 2]. (This could either evaluate the spread operation twice, or just copy the elements introduced by the first spread one more time).CONs:
x is an integer variable, then [x x x] is valid. More likely would be [x x length] or [value x x], which are still tricky to read because the same letter means different things.[for (var x in 0..42) ""], which is another way to reduce verbosity of loops. Or maybe even [for (0..42) ""] (where it would be a default variable name if you needed it). That is, if we had other shorthands, then x wouldn't be as needed, so it might be too specialized.extension<T> on List<T> {
List<T> operator*(int rhs) {
List<T> rv = [];
for (int i = 0; i < rhs; i++) {
rv.addAll(this);
}
return rv;
}
}
void main() {
final list = [2] * 42;
print(list);
}
Prints [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]
That's clever, but probably not as efficient as I'd want it. The reason for making it a language feature would be that it can be efficiently optimized, used inside list literals, and it'd be more convenient than List.generate(42, 2).
For [2] * 42 by itself, it's actually decently usable.
Inside another list, it will require a spread, so [1, ... [2] * 42,. 3] instead of [1, 2 x 42, 3]. Still close.
In practice I'd probably make it a method on Iterable, so it could also be used in set literals:
extension X on Iterable<T> {
Iterable<T> operator*(int repeat) {
RangeError.checkValueInRange, repeat, 0, null, "repeat");
return () sync* {
for (var i = 0; i < repeat; i++) yield* this;
}();
}
}
Then you would always need a spread: [...[2] * 42], {...[2] * 42}.
Most helpful comment
That's clever, but probably not as efficient as I'd want it. The reason for making it a language feature would be that it can be efficiently optimized, used inside list literals, and it'd be more convenient than
List.generate(42, 2).For
[2] * 42by itself, it's actually decently usable.Inside another list, it will require a spread, so
[1, ... [2] * 42,. 3]instead of[1, 2 x 42, 3]. Still close.In practice I'd probably make it a method on
Iterable, so it could also be used in set literals:Then you would always need a spread:
[...[2] * 42],{...[2] * 42}.