Ernesto
Ernesto

Reputation: 103

Is this perhaps a Dart bug?

While trying to update a List of List of Strings in a map using the short notation with the fat arrow I get "This expression has type 'void' and can't be used." error. If I don't use the short notation and instead use an intermediate variable and return it it works fine.

I'm trying to update a map of the following type:

Map<String, List<List<String>>> mapWithAListOfListsOfStrings = {};

This is the code using the fat arrow notation.

void main() {
  Map<String, List<List<String>>> mapWithAListOfListsOfStrings = {};
  String string1 = 'Lorem ipsum dolor sit amet';
  String string2 = 'consectetur adipiscing elit';

  for (String string in [string1, string2]) {
    List<String> splitString = string.split(' ');
    mapWithAListOfListsOfStrings.update('1', (list) => list.add(splitString), ifAbsent: () => [splitString]);
  }

  print("Map contains: ${mapWithAListOfListsOfStrings.toString()}");

}

This is the error I get:

sample.dart:8:56: Error: This expression has type 'void' and can't be used.
    mapWithAListOfListsOfStrings.update('1', (list) => list.add(splitString), ifAbsent: () => [splitString]);

This is my workaround that works:

void main() {
  Map<String, List<List<String>>> mapWithAListOfListsOfStrings = {};
  String string1 = 'Lorem ipsum dolor sit amet';
  String string2 = 'consectetur adipiscing elit';

  for (String string in [string1, string2]) {
    List<String> splitString = string.split(' ');
    mapWithAListOfListsOfStrings.update('1', (list) {
      List<List<String>> returnList = list;
      returnList.add(splitString);
      return returnList;
    }, ifAbsent: () => [splitString]);
  }

  print("Map contains: ${mapWithAListOfListsOfStrings.toString()}");

}

And this is the desired result:

Map contains: {1: [[Lorem, ipsum, dolor, sit, amet], [consectetur, adipiscing, elit]]}

I'm happy to leave it like that. I just wonder why the first approach throws an error.

Thanks in advance.

Upvotes: 0

Views: 96

Answers (1)

lrn
lrn

Reputation: 71653

The problem is indeed that the return type of list.add is void, and not the list itself. The update method requires its argument function to return the new value for the provided key, and => list.add(...) doesn't do that, it just returns void.

Your workaround could be reduced to:

(list) {
  list.add(splitString);
  return list;
}

or to:

(list) => list..add(splitString)

but the real problem is that you shouldn't be using map.update at all. That function is intended to replace the existing value for a key, not to keep the list value after adding something to it. You have to go out of your way to return the value again, instead of just using a function which doesn't change the value of the key (except if it isn't here).

I'd write it as:

mapWithAListOfListOfStrings.putIfAbsent('1', () =>[]).add(splitString);

The putIfAbsent returns the existing value, or inserts a value if there isn't one yet and then returns that value, so this really does:

  • Ensure that my map['1'] exists and is a list
  • Do map['1'].add(splitString)

It just does so without needing to look up '1' twice.

Upvotes: 1

Related Questions