Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CombinedMapView does not maintain keys uniqueness #595

Closed
renatoathaydes opened this issue Aug 14, 2019 · 11 comments · Fixed by dart-archive/collection#110
Closed

CombinedMapView does not maintain keys uniqueness #595

renatoathaydes opened this issue Aug 14, 2019 · 11 comments · Fixed by dart-archive/collection#110
Assignees

Comments

@renatoathaydes
Copy link

The following test fails:

final map = CombinedMapView([{'1': 1, '2': 2, '3': 3}, {'2': 22, '4': 44}]);
expect(map.length, equals(4));
expect(map.keys.toList(), equals(['1', '2', '3', '4']));

The first expectation fails because length returns 5.
The second, because keys returns ['1', '2', '3', '2', '4'].

This seems to violate Map's interface, which says:

There is a finite number of keys in the map, and each key has exactly one value associated with it.

This was a problem for me because I needed something that looks just like a normal Map but based on two other Maps, and which lets a map coming first "override" values on the map coming later in the list of maps. I believe that's the main purpose of combining maps (possibly unmodifiable), but due to this issue, it can't be used like that.

@jakemac53 jakemac53 self-assigned this Aug 14, 2019
@renatoathaydes
Copy link
Author

My workaround was creating my own type on top of it:

class SnapshotMap<K, V> extends CombinedMapView<K, V> {
  Iterable<K> Function() _lazyKeys;

  SnapshotMap(Map<K, V> topMap, Map<K, V> bottomMap)
      : super([topMap, bottomMap]) {
    _lazyKeys = lazy(() => super.keys.toSet());
  }

  UnmodifiableMapView<K, V> get view => UnmodifiableMapView(this);

  @override
  Iterable<K> get keys => _lazyKeys();

  @override
  int get length => keys.length;
}

@jakemac53
Copy link
Contributor

Ya, I am going to see if I can maintain the lazy behavior of the current implementation though if possible. Otherwise this would likely break some projects.

@renatoathaydes
Copy link
Author

No the prettiest thing, but my lazy function above:

T Function() lazy<T>(T Function() f) {
  T instance;
  return () {
    if (instance == null) {
      instance = f();
      if (instance == null) {
        throw StateError('lazy function must not return null');
      }
    }
    return instance;
  };
}

@jakemac53
Copy link
Contributor

The problem there is the toSet call ends up eagerly iterating all the keys of all the maps as soon as you ask for the first key - I have a simple implementation coming though.

@jakemac53
Copy link
Contributor

Note that in adding the test for this I also noticed forEach and values were broken, fun!

@jakemac53
Copy link
Contributor

(these all get fixed by fixing keys though)

@renatoathaydes
Copy link
Author

That's true, but if you avoid that you'll have to check for already-iterated keys on all maps except the first... which may be more costly?! Unless perhaps if you accumulate keys as you see them into a set?

@jakemac53
Copy link
Contributor

Yes I am accumulating them as i see them, the impl is actually really easy/small.

jakemac53 referenced this issue in dart-archive/collection Aug 16, 2019
Fixes https://github.com/dart-lang/collection/issues/109

Adds a custom iterable/iterator that can filter out duplicates and use that for the `CombineMapView.keys` getter. 

Updates tests to contain duplicates in maps, and ensure the keys/values from the earlier maps are the ones that are returned.

Updates the changelog and docs to no longer claim `O(maps)` for the length getter. This now requires iteration of all items and is `O(total map entries)`.

Prepare to publish as 1.14.12
@renatoathaydes
Copy link
Author

@jakemac53 is this going to be released soon?

@jakemac53
Copy link
Contributor

Yes, should be very soon (waiting for an existing publisher to add me as an uploader or publish it themselves).

@jakemac53
Copy link
Contributor

This is now published as version 1.14.12

mosuem referenced this issue Oct 18, 2024
Fixes https://github.com/dart-lang/collection/issues/109

Adds a custom iterable/iterator that can filter out duplicates and use that for the `CombineMapView.keys` getter. 

Updates tests to contain duplicates in maps, and ensure the keys/values from the earlier maps are the ones that are returned.

Updates the changelog and docs to no longer claim `O(maps)` for the length getter. This now requires iteration of all items and is `O(total map entries)`.

Prepare to publish as 1.14.12
@mosuem mosuem transferred this issue from dart-archive/collection Oct 21, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants