-
Notifications
You must be signed in to change notification settings - Fork 4k
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
Implement ImmutableSegmentedDictionary<TKey, TValue> #50189
Implement ImmutableSegmentedDictionary<TKey, TValue> #50189
Conversation
This comparer is not required by IImmutableDictionary<TKey, TValue> and is not directly supported by SegmentedDictionary<TKey, TValue>. Removing the property and relying on EqualityComparer<TValue>.Default allows for more efficient wrapper implementation.
8fa13a5
to
8ecf29e
Compare
src/Dependencies/Collections/ImmutableSegmentedDictionary`2+Builder.cs
Outdated
Show resolved
Hide resolved
src/Dependencies/Collections/ImmutableSegmentedDictionary`2+Builder.cs
Outdated
Show resolved
Hide resolved
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
using System; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need to add #nullable enable
so that it gets enabled in projects that don't have it enabled by default.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
➡️ The current code follows the patterns established in the Microsoft.CodeAnalysis.PooledObjects.Package package. If we want to change the way we annotate source packages, we can do so but it should be a separate pull request that includes validation to prevent subtle regressions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good. Let's follow up.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
➡️ #50749
src/Dependencies/Collections/ImmutableSegmentedDictionary`2+PrivateInterlocked.cs
Show resolved
Hide resolved
Done review pass (commit 4) |
src/Dependencies/Collections/ImmutableSegmentedDictionary`2+PrivateInterlocked.cs
Outdated
Show resolved
Hide resolved
|
||
namespace Microsoft.CodeAnalysis.Collections | ||
{ | ||
internal static class RoslynImmutableInterlocked |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
RoslynImmutableInterlocke [](start = 26, length = 25)
I'd move these helpers to ImmutableSegmentedDictionary
static class. Exposing "RoslynImmutableInterlocked" type is odd.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
➡️ This type is intentionally designed as a drop-in replacement for code currently using ImmutableInterlocked
with ImmutableDictionary<TKey, TValue>
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That may be, but I don't like these type names. You can drop-in replace as well, just use different type names.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These names follow the pattern of RoslynDebug
and RoslynString
. The methods it contains are exactly the same as the methods in ImmutableInterlocked
(signatures and semantics), but with signatures adjusted to work with our types in ways that ImmutableInterlocked
does not support. I can rename this to ImmutableInterlocked
as soon as C# is updated to allow static extensions to existing static classes.
The name can't otherwise be changed without actively interfering with a-priori developer knowledge.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
RoslynDebug and RoslynString are internal types limited to Roslyn repo and not exposed by a source package. What if we had another type that needs interlocked operations? Are we gonna have RoslynImmutableInterlocked2
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ImmutableInterlocked provides atomic operations for all of the immutable collections types.
That would require either static extension methods or all immutable types defined in the same assembly.
Other members are going to be added to this type when ImmutableSegmentedList is added
SegmentedCollectionsInterlocked
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That works for ImmutableSegmentedDictionary<TKey, TValue>
and ImmutableSegmentedList<T>
, but not for ImmutableArrayDictionary<TKey, TValue>
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll file a follow-up issue to discuss naming for static helper types in source packages.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the plan to move these to System.Collections.Immutable at some point?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Filed #50750. Moving to System.Collections.Immutable is an option, though I'm not sure if/when that would occur.
2ffe81e
to
54600cd
Compare
|
||
mutable.Add(1, "a"); | ||
var immutable2 = mutable.ToImmutable(); | ||
Assert.NotSame(immutable1, immutable2); // "Mutating the collection did not reset the Immutable property." | ||
Assert.Same(immutable2, mutable.ToImmutable()); // "The Immutable property getter is creating new objects without any differences." | ||
Assert.False(immutable1 == immutable2); // "Mutating the collection did not reset the Immutable property." |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider using Equal
/NotEqual
for these, rather than True
/False
with operators, as that will give better errors.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test is leveraging the fact that ==
implements reference equality for these collections (similar to ImmutableArray<T>
). While Equals
technically would do the same thing for this type, it feels one step further removed because it looks like value equality is intended by the test when we're really looking for reference equality.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't believe that outweighs the benefits from getting clear error messages.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
➡️ Switched to Assert.False(IsSame(...))
to match the other cases
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't believe that addresses my comments about error messages.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is correct, but also By Design in accordance with our adopted test framework (see xunit/xunit#350 for additional discussion). The approach used by this pull request adheres to the test framework recommendation that the assertion call site clearly show the intent of the assertion, which IsSame
will do.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not going to block the PR over the test comments, but I really would prefer if our tests had good error messages for failures.
Provides an implementation of
IImmutableDictionary<TKey, TValue>
which is backed bySegmentedDictionary<TKey, TValue>
. The immutable wrapper is a value type, offering benefits similar to the cases whereImmutableArray<T>
is more appropriate thanImmutableList<T>
. The implementation preserves all functionality fromImmutableDictionary<TKey, TValue>
(intended to be a near drop-in replacement), with the following exceptions:ImmutableDictionary<TKey, TValue>
is customizable through theValueComparer
property, but this collection always usesEqualityComparer<TValue>.Default
ImmutableDictionary<TKey, TValue>
does not provide struct enumerators for theKeys
orValues
property (Memory allocation documentation for ImmutableDictionary Keys and Values runtime#13927), butImmutableSegmentedDictionary<TKey, TValue>
does