https://dart.dev/language/collections#control-flow-operators[`for` elements] should be preferred to https://api.dart.dev/stable/dart-core/Map/Map.fromIterable.html[`fromIterable`] when building a https://api.dart.dev/stable/dart-core/Map/Map.html[`Map`] from an https://api.dart.dev/stable/dart-core/Iterable-class.html[`Iterable`].

== Why is this an issue?

While it is possible to build a `Map` from an `Iterable` using `Map.fromIterable`, writing an explicit `for` loop with `for` elements should be used instead.

The main reason to prefer `for` elements is that it can be optimized by the Dart compiler for performance, depending on the iterable being visited.

Moreover, `for` elements are more idiomatic and generally easier to understand than `Map.fromIterable`, which requires explicit map type upfront, as well as the input iterable and two different lambda functions as parameters.

[source,dart]
----
Map<String, int>.fromIterable( // Explicit Map<String, int> type required
  inputIterable,
  key: (item) => ...,          // Key generator
  value: (item) => ...,        // Value generator
);
----

On the other hand, `for` elements are more flexible, look like normal `for` loops, and support better inference of the resulting `Map` type.

[source,dart]
----
{
    for (final item in inputIterable)
        'The value is $v': v // Implicit Map<String, int> type inference
}
----

=== Exceptions

The rule only applies to the `fromIterable` factory method of `Map`. It does not apply to other `fromIterable` methods, such as the one from `LinkedHashMap<T, U>` in `dart:collection`.

Moreover, it only applies when all the arguments of the `Map.fromIterable` call are provided. If either the `key` or the `value` parameter is omitted, the rule does not apply.

[source,dart]
----
Map<int, int>.fromIterable(l1, key: (item) => ...); // OK
Map<int, int>.fromIterable(l1, value: (item) => ...); // OK
----

The rule also does not apply when the `key` and `value` parameters are not inline function expressions, but variables defined elesewhere in the code.

[source,dart]
----
final key = (item) => ...;
final value = (item) => ...;
Map<int, int>.fromIterable(l1, key: key, value: value);
----

== How to fix it

In order to replace `Map.fromIterable` with `for` elements:

* replace the `Map<String, int>.fromIterable` call with a `for` loop over the input iterable, that is the first argument of the call
* define the body of the `for` elements as a `key: value` pair, where `key` is the body of the key generator lambda, and `value` is body of the value generator lambda

=== Code examples

==== Noncompliant code example

[source,dart,diff-id=1,diff-type=noncompliant]
----
Map<String, int>.fromIterable(
  [1, 2, 3],
  key: (v) => 'The value is $v',
  value: (v) => v,
);
----

==== Compliant solution

[source,dart,diff-id=1,diff-type=compliant]
----
{
    for (final v in [1, 2, 3])
        'The value is $v': v
}
----

== Resources

=== Documentation

* Dart Docs - https://dart.dev/tools/linter-rules/prefer_for_elements_to_map_fromIterable[Linter rule - prefer_for_elements_to_map_fromIterable]
* Dart Docs - https://dart.dev/language/collections#control-flow-operators[Language - Control-flow operators]
* Dart API Reference - https://api.dart.dev/stable/dart-core/Map/Map.html[Map<K, V> class]
* Dart API Reference - https://api.dart.dev/stable/dart-core/Iterable-class.html[Iterable<E> class]
* Dart API Reference - https://api.dart.dev/stable/dart-core/Map/Map.fromIterable.html[Map<K, V>.fromIterable constructor]


ifdef::env-github,rspecator-view[]

'''
== Implementation Specification
(visible only on this page)

=== Message

Use 'for' elements when building maps from iterables.

=== Highlighting

The entire `Map.fromIterable` call, including parentheses and arguments: e.g. `Map<String, int>.fromIterable([1, 2, 3], key: (v) => 'The value is $v', value: (v) => v);`.

endif::env-github,rspecator-view[]
