I noticed that forEach
and for in
to produce different behavior. I have a list of RegExp
and want to run hasMatch
on each one
Despite the prefer_foreach lint, IMO, generally avoid using Iterable.forEach
. Except for simple, specialized cases where the callback is a tearoff (a reference to an existing function), I don't think that it's any simpler than using a basic and more general for
loop. There are more pitfalls using forEach
, and this is one of them.
Iterable.forEach
is a function that takes a callback as an argument. Iterable.forEach
is not a control structure, and the callback is an ordinary function. You therefore cannot use break
to stop iterating early or use continue
to skip to the next iteration.
A return
statement in the callback returns from the callback, and the return value is ignored. The caller of Iterable.forEach
will never receive the returned value and will never have an opportunity to propagate it. For example, in:
bool f(List<int> list) {
for (var i in list) {
if (i == 42) {
return true;
}
}
return false;
}
the return true
statement returns from the function f
and stops iteration. In contrast, with forEach
:
bool g(List<int> list) {
list.forEach((i) {
if (i == 42) {
return true;
}
});
return false;
}
the return true
statement returns from only the callback. The function g
will not return until it completes all iterations and reaches the return false
statement at the end. This perhaps is clearer as:
bool callback(int i) {
if (i == 42) {
return true;
}
}
bool g(List<int> list) {
list.forEach(callback);
return false;
}
which makes it more obvious that:
callback
to cause g
to return true
.callback
does not return a value along all paths.(That's the problem you encountered.)
Iterable.forEach must not be used with asynchronous callbacks. Because any value returned by the callback is ignored, asynchronous callbacks can never be waited upon.
I should also point out that if you enable Dart's new null-safety features, which enable stricter type-checking, your forEach
code will generate an error because it returns a value in a callback that is expected to have a void
return value.