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

Fix selection being dropped when changing carousel sort mode from difficulty sort #29786

Merged
merged 2 commits into from
Sep 8, 2024

Conversation

bdach
Copy link
Collaborator

@bdach bdach commented Sep 8, 2024

Closes #29738.

This "regressed" in #29639, but if I didn't know better, I'd go as far as saying that this looks like a .NET bug, because the fact that PR broke it looks not sane.

The TL;DR on this is that before the pull in question, the offending .Contains() check that this commit modifies was called on a List<BeatmapSetInfo>. The pull changed the collection type to BeatmapSetInfo[]. That said, the call is a LINQ call, so all good, right?

Not really. First off, the default overload resolution order means that the previous code would call List<T>.Contains(), and not Enumerable.Contains<T>(). Then again, why would that matter? In both cases T is still BeatmapSetInfo, right? Well... about that...

It is difficult to tell for sure what precisely is happening here, because of what looks like runtime magic. The end symptom is that the old code ended up calling Array<BeatmapSetInfo>.IndexOf(), and the new code ends up calling... Array<object>.IndexOf().

So while yes, BeatmapSetInfo implements IEquatable and the expectation would be that Equals<BeatmapSetInfo>() should be getting called, the type elision to object means that we're back to reference equality semantics, because that's what EqualityComparer.Default<object> is.

A five-minute github search across dotnet/runtime yields this. Now again, if I didn't know better, I'd see that "OPTIMIZATION:" comment, see what transpired in this scenario, and call that optimisation invalid, because it changes semantics. But I probably know that the dotnet team knows better and am probably just going to take it for what it is, because blame on that code looks to be years old and it's probably not a new behaviour. (I haven't tested empirically if it is.)

Instead the fix is just to tell the .Contains() method to use the correct comparer.

…ficulty sort

Closes ppy#29738.

This "regressed" in ppy#29639, but if I
didn't know better, I'd go as far as saying that this looks like a .NET
bug, because the fact that PR broke it looks not sane.

The TL;DR on this is that before the pull in question, the offending
`.Contains()` check that this commit modifies was called on a
`List<BeatmapSetInfo>`. The pull changed the collection type to
`BeatmapSetInfo[]`. That said, the call is a LINQ call, so all good,
right?

Not really. First off, the default overload resolution order means that
the previous code would call `List<T>.Contains()`, and not
`Enumerable.Contains<T>()`. Then again, why would that matter? In both
cases `T` is still `BeatmapSetInfo`, right? Well... about that...

It is difficult to tell for sure what precisely is happening here,
because of what looks like runtime magic. The end *symptom* is that the
old code ended up calling `Array<BeatmapSetInfo>.IndexOf()`, and the new
code ends up calling... `Array<object>.IndexOf()`.

So while yes, `BeatmapSetInfo` implements `IEquatable` and
the expectation would be that `Equals<BeatmapSetInfo>()` should be
getting called, the type elision to `object` means that we're back to
reference equality semantics, because that's what
`EqualityComparer.Default<object>` is.

A five-minute github search across dotnet/runtime yields this:

	https://github.com/dotnet/runtime/blob/c4792a228ea36792b90f87ddf7fce2477e827822/src/coreclr/vm/array.cpp#L984-L990

Now again, if I didn't know better, I'd see that "OPTIMIZATION:"
comment, see what transpired in this scenario, and call that
optimisation invalid, because it changes semantics. But I *probably*
know that the dotnet team knows better and am probably just going to
take it for what it is, because blame on that code looks to be years
old and it's probably not a new behaviour. (I haven't tested empirically
if it is.)

Instead the fix is just to tell the `.Contains()` method to use the
correct comparer.
@bdach bdach added area:song-select next release Pull requests which are almost there. We'll aim to get them in the next release, but no guarantees! labels Sep 8, 2024
@bdach bdach requested a review from a team September 8, 2024 14:10
@peppy peppy self-requested a review September 8, 2024 14:35
@@ -520,7 +520,6 @@ public void TestAddRemove()
waitForSelection(set_count);
}

[Solo]
Copy link
Member

Choose a reason for hiding this comment

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

We probably need an inspection for this 😅

@peppy peppy merged commit e836062 into ppy:master Sep 8, 2024
11 of 13 checks passed
@bdach bdach deleted the fix-difficulty-sort-selection-change branch September 8, 2024 15:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area:song-select next release Pull requests which are almost there. We'll aim to get them in the next release, but no guarantees! size/S
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Changing sort mode from difficulty to any other loses track of previous selection
2 participants