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

[API Proposal]: Remove where T : IEquatable<T>? constraint from MemoryExtensions methods #75639

Open
stephentoub opened this issue Sep 14, 2022 · 10 comments
Labels
api-suggestion Early API idea and discussion, it is NOT ready for implementation area-System.Memory
Milestone

Comments

@stephentoub
Copy link
Member

stephentoub commented Sep 14, 2022

We should consider removing this constraint. It inhibits the use of almost all of the methods for Ts that would otherwise functionally work fine via EqualityComparer<T>.Default.Equals and adds relatively little benefit. Notably SequenceEqual and CommonPrefixLength don't have the constraint, but most everything else on MemoryExtensions does.

@stephentoub stephentoub added api-suggestion Early API idea and discussion, it is NOT ready for implementation area-System.Memory labels Sep 14, 2022
@stephentoub stephentoub added this to the 8.0.0 milestone Sep 14, 2022
@ghost
Copy link

ghost commented Sep 14, 2022

Tagging subscribers to this area: @dotnet/area-system-memory
See info in area-owners.md if you want to be subscribed.

Issue Details

We should consider removing this constraint. It inhibits the use of almost all of the methods for Ts that would otherwise functionally work fine via EqualityComparer<T>.Default.Equals and adds relatively little benefit.

Author: stephentoub
Assignees: -
Labels:

api-suggestion, area-System.Memory

Milestone: 8.0.0

@jkotas
Copy link
Member

jkotas commented Sep 15, 2022

SequenceEqual and CommonPrefixLength don't have the constrain

SequenceEqual has the constrain: https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/MemoryExtensions.cs#L966

@stephentoub
Copy link
Member Author

SequenceEqual has the constrain:

That overload does. We added this overload (which optionally accepts a comparer) which does not:

public static bool SequenceEqual<T>(this Span<T> span, ReadOnlySpan<T> other, IEqualityComparer<T>? comparer = null) =>

@stephentoub
Copy link
Member Author

stephentoub commented Sep 15, 2022

Also note in the API review for that overload:
#48304 (comment)
"We could drop the constraint on the existing APIs and do the right thing internally, but we can do that later"

As an alternative to just dropping the constraint (or in addition to), we could also add new overloads of all the relevant methods, similarly without a constraint and similarly accepting an optional comparer.

@jkotas
Copy link
Member

jkotas commented Sep 15, 2022

We have introduced the IEquatable<T> constraint on these methods to avoid paying for EqualityComparer<T> overhead. The JIT can optimize the EqualityComparer<T>.Default pretty well for (non-generic) structs today, but these optimizations still do not kick in for shared generics. Dropping the IEquatable<T> constraint would likely introduce regressions for cases where T is a reference type.

@stephentoub
Copy link
Member Author

stephentoub commented Sep 15, 2022

I'd be fine with the alternative if we believe we won't be able to solve those T==reference type overheads:
"As an alternative to just dropping the constraint (or in addition to), we could also add new overloads of all the relevant methods, similarly without a constraint and similarly accepting an optional comparer."

It's more overloads / more implementation (assuming we want to keep the separate implementations to avoid the shared generics overhead in the existing methods), but it's also more flexible, enabling the algorithms to be reused even with alternate comparison logic, and it wouldn't penalize existing usage, just enable usage not currently possible.

@stephentoub
Copy link
Member Author

stephentoub commented Jan 16, 2024

Just bumped into this again today. I wanted the equivalent of IndexOfAnyExcept(null) for an array of reference types. We don't appear to have anything to do that efficiently right now without using unsafe code that depends on runtime internal implementation details.

@tannergooding
Copy link
Member

Would this potentially be a reason to push harder on bridged generic constraints so that users aren't completely blocked or do we think its better to just expose both sets of overloads?

@stephentoub
Copy link
Member Author

Would this potentially be a reason to push harder on bridged generic constraints so that users aren't completely blocked or do we think its better to just expose both sets of overloads?

That wouldn't really help with this particular case, since the target legitimately doesn't implement the constraint. I think we need both features.

@tannergooding
Copy link
Member

Seems like the best option would be to add the overloads then, given the concern around impact to shared generics (and runtimes like Mono where shared generics are all they really have)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api-suggestion Early API idea and discussion, it is NOT ready for implementation area-System.Memory
Projects
None yet
Development

No branches or pull requests

3 participants