Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.
/ corefx Public archive

Enumerate over dictionary keys and values without allocations #246

Closed
wants to merge 1 commit into from

Conversation

sharwell
Copy link
Member

This pull request offers an alternative to #147. It eliminates the allocations when evaluating the Keys and Values properties of ImmutableDictionary<TKey, TValue>, but does so without increasing the allocated size of an ImmutableDictionary<TKey, TValue> instance.

The documentation associated with the members created by this pull request do not currently meet my own quality standards, but I sent the pull request before going through that part in detail in order to get early feedback. If the community believes this approach is the desired implementation for this functionality, I will go back through the documentation in detail.

@@ -166,34 +166,44 @@ public IEqualityComparer<TValue> ValueComparer
/// <summary>
/// Gets the keys in the map.
/// </summary>
public IEnumerable<TKey> Keys
public KeyCollection Keys
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately, this is a breaking change that would prevent applications built against the stable 1.0 immutable collections from running against the new version. We preserve binary compatibility between stable package versions and therefore I don't think we can make this transformation.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for taking a look. I wasn't sure what breaking changes policy was in place since no stable releases of System.Collections.Immutable have appeared on NuGet yet. I see now that the changes are also evaluated against the stable release of Microsoft.Bcl.Immutable.

Tomorrow I'll update this pull request to revert the change to this property and instead expose the KeyCollection and ValueCollection constructors, which allows users to use instances of these types without incurring allocations. Use of the Keys and Values properties will require a boxing allocation but should be slightly more efficient overall than the current iterator implementation.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could just change the return type to IEnumerable<TKey/TValue> and it should be binary compatible

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pdelvo In other words revert this part of the change as @sharwell suggested he'd do next? :)

I don't think the extra code for the key and value enumeration is worth it if won't save on boxing for existing code. Consumers needing maximum efficiency can already get it with just one extra line of code:

Before:

foreach (var key in dictionary.Keys) {
   ...
}

After:

foreach (var pair in dictionary) {
    var key = pair.Key;
    ...
}

As such, I suggest we leave things as they are.

@AArnott
Copy link

AArnott commented Dec 14, 2014

I agree with @nguerrera. This would be significantly more code without avoiding the allocation. Efficiency/perf improvements need a real world driver to justify added code/complexity that more than pays for the cost of maintaining/shipping the added code. I don't see that here.

I appreciate your intent @sharwell, and I look forward to more of your contributions in the future.

@sharwell
Copy link
Member Author

I think @nguerrera and @AArnott pointed out the real problem here and with #147 and didn't realize it. See #249. 😄 I created an issue rather than a pull request because I'm not sure what wording to use with respect to the caveat I listed.

@sharwell sharwell closed this Dec 14, 2014
@sharwell
Copy link
Member Author

@nguerrera @AArnott I'm working on a library to [eventually] automate detection of this kind of API problem by comparing a current build to a previous release obtained from NuGet during the testing phase. I'd love it if you could add issues to the repository describing the types of changes you would consider "breaking changes".

https://github.com/rackerlabs/dotnet-compatibility

@nguerrera
Copy link
Contributor

@sharwell Very cool. We actually have a similar tool that we've written internally. I will ask if we can open source it or at least share the full set of rules we implement. We do have documentation around what we consider breaking here:

https://github.com/dotnet/corefx/wiki/breaking-changes
https://github.com/dotnet/corefx/wiki/breaking-change-definitions
https://github.com/dotnet/corefx/wiki/breaking-change-rules

@sharwell
Copy link
Member Author

@nguerrera That would be awesome. One of the advantages of the one I'm working on is it doesn't require the ability to resolve referenced assemblies (it takes advantage of the System.Reflection.Metadata package for this). Does your tool do something similar in this regard?

@nguerrera
Copy link
Contributor

@sharwell Sweet. I love to see more System.Reflection.Metadata adoption. :)

We currently use CCI: http://ccimetadata.codeplex.com/

Note that there will be cases where you'll need to resolve references: e.g. to validate that a change of base type is OK because the old base type is still an ancestor.

@nguerrera
Copy link
Contributor

@sharwell I'm also working on a better signature reading API that will help you clean up some code and handle some of the cases marked TODO more easily. Expect it to show up in January.

@sharwell
Copy link
Member Author

@nguerrera I'm not seeing the issues for that 😑

On a serious note, I'd be interested in reviewing the API and possibly helping with the implementation and documentation. I've written a metadata reader from scratch and used them in many applications.

Edit: A placeholder #262 has been added now.

@nguerrera
Copy link
Contributor

@sharwell Sounds great. This API will be targeted at a 1.1 release of System.Reflection.Metadata and we'll have plenty of time to iterate on the design, docs, and implementation. Help will be most appreciated. I'm swamped with other things from now through January, but I'll get the initial implementation and a mini-spec for review up in the new year.

@karelz karelz modified the milestone: 1.0.0-rtm Dec 3, 2016
Olafski pushed a commit to Olafski/corefx that referenced this pull request Jun 15, 2017
Remove .DS_Store file from repo
MaximLipnin pushed a commit to MaximLipnin/corefx that referenced this pull request Mar 12, 2019
…ams (C# 8.0). (dotnet#246)

Bring some code from corefx master for async-streams (C# 8.0):

- `IAsyncEnumerable`
- `IAsyncEnumerator`
- `IAsyncDisposable`
- `AsyncIteratorStateMachineAttribute`
- `AsyncIteratorMethodBuilder`
- `ManualResetValueTaskSourceCore`

Minor changes to existing code:

- Add `ExecutionContext.ContextCallback<TState>(ref TState state)` delegate.
- Add `ExecutionContext.RunInternal<TState>` method.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants