-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
Make mutable generic collection interfaces implement read-only collection interfaces #95830
Conversation
Tagging subscribers to this area: @dotnet/area-system-collections Issue DetailsCloses #31001
|
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.
You also need to update the reference sources at https://github.com/dotnet/runtime/blob/main/src/libraries/System.Runtime/ref/System.Runtime.cs.
Thanks, done. I assumed they were auto-generated given how they looked with fully qualified names. |
The assert is in GetActualImplementationForArrayGenericIListOrIReadOnlyListMethod in |
I'm sorry, I'm not well versed in c++. From what I gather from that method we use the inheritance depth to determine the starting method but with this change the inheritance depth of |
Yes, the inheritance depth optimization is not going work. To get unblocked, you can try deleting it and call |
@@ -53,5 +53,7 @@ bool IsReadOnly | |||
[DynamicDependency(nameof(Array.InternalArray__ICollection_Remove) + "``1", typeof(Array))] | |||
#endif | |||
bool Remove(T item); | |||
|
|||
int IReadOnlyCollection<T>.Count => Count; |
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.
@eiriktsarpalis, if we end up keeping this inheritance, that will tip the scales for special-casing IReadOnlyXx in LINQ: in particular for places where we only need the source's count, we'll want to look for IReadOnlyCollection rather than ICollection, since every occurrence of the latter will also be the former.
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 believe it was decided to not make any changes in .NET 9 that would rely on this inheritance hierarchy change in case it needs to be reverted late in the cycle.
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.
Note that going to the default implemented method (that in turn calls another interface method) will involve a double interface dispatch. It remains to be seen how well (if at all) dynamic pgo will be able to get rid of it. The callsite in the default implementation is going to be megamorphic.
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.
Note that going to the default implemented method (that in turn calls another interface method) will involve a double interface dispatch.
Could the runtime optimize this to make the IReadOnlyCollection<T>.Count
slot point directly to the ICollection<T>.Count
? That way we could avoid the double interface dispatch.
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.
Isn't this also something PGO can help with?
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 way PGO works is that it will collect all the possible types of this
it saw at the callsite and then generate a cascade of if (thisType.GetType() == typeof(Foo)) Foo.Method();
. There's a limit on how many checks can be generated that way, and each check has a cost. The more types you have that implement the ICollection but not IReadOnlyCollection, the worse it gets.
You'll typically not see this in microbenchmarks because those typically repeat the same thing over and over and dynamic PGO is really good at optimizing things that are repeated the same way over and over.
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 double dispatch is largely a point in time problem.
None of the built-in BCL types will actually hit it, because we provide an actual implementation. Downstream implementers are either already implementing both ICollection<T>
and IReadOnlyCollection<T>
or can be pointed towards doing so with an analyzer so they don't incur the double dispatch either.
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 believe it was decided to not make any changes in .NET 9 that would rely on this inheritance hierarchy change in case it needs to be reverted late in the cycle.
But it could/would be done for .NET 10 (provided this change stays)?
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 believe it was decided to not make any changes in .NET 9 that would rely on this inheritance hierarchy change in case it needs to be reverted late in the cycle.
But it could/would be done for .NET 10 (provided this change stays)?
I don't agree with the stance and plan to submit a PR once this goes in. If we're confident enough to make this change at this point, we have to be fine with subsequent changes being based on it, as they absolutely will be whether intentionally or not. And it's no worse reverting one large PR and one small PR than one large PR if we decide we must.
I'm a bit out of my depth when it comes to these .NET Native AOT errors. Can anyone point me in the right direction here? |
I can help with that later but there's plenty of not-nativeaot failures to look at (the details already expired from the ci). |
I've merged the latest main to trigger a fresh build, hopefully we can take a closer look at the failures there. |
These benchmark links lead to 401 pages; would it be possible to make them publicly available? (.. Or give me access? 🫠) I'm intrigued by what's in it |
@KennethHoff the fact that you have to use the link is a bug (we need to update some credentials), the results should appear automatically on this PR. I will paste them manually. The link is useful for MS devs to investigate these issues. |
No significant improvement or regression on these benchmarks. Json
Plaintext
Fortunes
|
Added When you commit this breaking change:
Tagging @dotnet/compat for awareness of the breaking change. |
Our current plan is to get the PR merged today by EOD today, in time for the change to make it for Preview 4. |
We need this change included in the Preview4 snap and the merge-on-green restriction is blocking us because a couple of failures are not getting linked to KnownBuildError issues as expected. @tannergooding has confirmed the failures are all unrelated, so I will bypass the requirements and merge it. |
…y collection interfaces (dotnet#95830)" This reverts commit a2bd583.
…y collection interfaces (#95830)" (#101644) * Revert "Update ICollection<T> usage to IReadOnlyCollection<T> where applicable (#101469)" This reverts commit e92b7d0. * Revert "Make mutable generic collection interfaces implement read-only collection interfaces (#95830)" This reverts commit a2bd583. * Update src/coreclr/System.Private.CoreLib/src/System/Array.CoreCLR.cs
…tion interfaces (dotnet#95830) * Make mutable generic collection interfaces implement read-only collection interfaces * More updates * Fix build * Update refs * Add DIM's to ref also * fixes * Try to fix arrays * Moved dim's to the end of the interfaces. Made the tests support .NET Framework 4.8. * Small fix * Small fix * Fix build * Fix * Cleanup * Incorporate dotnet#96672 * Check the correct inheritanceDepth in vm/array.cpp --------- Co-authored-by: Eirik Tsarpalis <eirik.tsarpalis@gmail.com> Co-authored-by: Tanner Gooding <tagoo@outlook.com>
…y collection interfaces (dotnet#95830)" (dotnet#101644) * Revert "Update ICollection<T> usage to IReadOnlyCollection<T> where applicable (dotnet#101469)" This reverts commit e92b7d0. * Revert "Make mutable generic collection interfaces implement read-only collection interfaces (dotnet#95830)" This reverts commit a2bd583. * Update src/coreclr/System.Private.CoreLib/src/System/Array.CoreCLR.cs
…tion interfaces (dotnet#95830) * Make mutable generic collection interfaces implement read-only collection interfaces * More updates * Fix build * Update refs * Add DIM's to ref also * fixes * Try to fix arrays * Moved dim's to the end of the interfaces. Made the tests support .NET Framework 4.8. * Small fix * Small fix * Fix build * Fix * Cleanup * Incorporate dotnet#96672 * Check the correct inheritanceDepth in vm/array.cpp --------- Co-authored-by: Eirik Tsarpalis <eirik.tsarpalis@gmail.com> Co-authored-by: Tanner Gooding <tagoo@outlook.com>
…y collection interfaces (dotnet#95830)" (dotnet#101644) * Revert "Update ICollection<T> usage to IReadOnlyCollection<T> where applicable (dotnet#101469)" This reverts commit e92b7d0. * Revert "Make mutable generic collection interfaces implement read-only collection interfaces (dotnet#95830)" This reverts commit a2bd583. * Update src/coreclr/System.Private.CoreLib/src/System/Array.CoreCLR.cs
Closes #31001