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]: ConditionalWeakTable<TKey,TValue>.Remove overload #111925

Closed
Sergio0694 opened this issue Jan 28, 2025 · 8 comments · Fixed by #112263
Closed

[API Proposal]: ConditionalWeakTable<TKey,TValue>.Remove overload #111925

Sergio0694 opened this issue Jan 28, 2025 · 8 comments · Fixed by #112263
Assignees
Labels
api-approved API was approved in API review, it can be implemented area-System.Runtime.CompilerServices in-pr There is an active PR which will close this issue when it is merged
Milestone

Comments

@Sergio0694
Copy link
Contributor

Sergio0694 commented Jan 28, 2025

Background and motivation

ConditionalWeakTable<TKey, TValue> has a Remove method that internally also retrieves the removed item, if present, but does not surface it. There is no existing method on it that allows removing an item while also getting the removed item, if present. This makes it unnecessarily expensive to opportunistically remove items while also doing something with them (eg. removing them from some other data structure).

Eg. we hit this in the Windows Community Toolkit (CommunityToolkit/Windows#569):

if (_debounceInstances.TryGetValue(timer, out Action? action))
{
    _debounceInstances.Remove(timer); // Repeated lookup 🙁
    action.Invoke();
}

It would be nice to just be able to do this with a single API, which would be simpler to read and also more efficient:

if (_debounceInstances.Remove(timer, out Action? action))
{
    action.Invoke();
}

The new API would also make the whole operation atomic, which is also nice to have and might be necessary in some scenarios.

Implementing the new API is trivial, as ConditionalWeakTable<TKey, TValue> already has the necessary logic, just not exposed.

API Proposal

namespace System.Runtime.CompilerServices;

public sealed class ConditionalWeakTable<TKey, TValue>
{
    public bool Remove(TKey key);
+   public bool Remove(TKey key, [MaybeNullWhen(false)] out TValue value);
}

API Usage

Updating the example above to use the new API:

if (_debounceInstances.Remove(timer, out Action? action))
{
    action.Invoke();
}

Alternative Designs

Keep using TryGetValue + Remove, and waste an extra lookup. Also the whole thing is not atomic. And it's clunkier.

Risks

None, it's just a new convenience API with a well known signature also used on lots of other similar data structures.

@Sergio0694 Sergio0694 added api-suggestion Early API idea and discussion, it is NOT ready for implementation area-System.Runtime.CompilerServices labels Jan 28, 2025
@dotnet-policy-service dotnet-policy-service bot added the untriaged New issue has not been triaged by the area owner label Jan 28, 2025
Copy link
Contributor

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

@Sergio0694
Copy link
Contributor Author

@eiriktsarpalis small follow up to #89002, if you will. Would you be able to help get this to API review? 😄
Thank you!

@michael-hawker
Copy link

michael-hawker commented Jan 28, 2025

This would also match the existing patterns established by other collections like ConcurrentDictionary which we were using before migrating to ConditionalWeakTable, which is how Sergio discovered this gap when reviewing our change.

RE: https://learn.microsoft.com/en-us/dotnet/api/system.collections.concurrent.concurrentdictionary-2.tryremove?view=net-9.0

@michael-hawker
Copy link

Was just thinking broader beyond this; in the future, should TryRemove be on the base IDictionary<TKey,TValue> where TryGetValue and Remove come from?

@Sergio0694
Copy link
Contributor Author

Note that ConcurrentWeakTable<,> is intentionally not a dictionary (even though it's similar to one).
That should be in its own separate proposal (though it'd seem like a tough sell to me, as it'd be a new interface method).

@eiriktsarpalis
Copy link
Member

Note that the existing Remove returns a boolean and is effectively already a "TryRemove" (it has the same signature and behavior as the TryRemove method in ConcurrentDictionary). So to me this feels like it should be an overload to Remove as opposed to a separate method group.

@Sergio0694 Sergio0694 changed the title [API Proposal]: ConditionalWeakTable<TKey,TValue>.TryRemove [API Proposal]: ConditionalWeakTable<TKey,TValue>.Remove overload Jan 29, 2025
@Sergio0694
Copy link
Contributor Author

Makes sense to me, updated! 🙂

@eiriktsarpalis eiriktsarpalis added api-ready-for-review API is ready for review, it is NOT ready for implementation and removed api-suggestion Early API idea and discussion, it is NOT ready for implementation untriaged New issue has not been triaged by the area owner labels Jan 29, 2025
@eiriktsarpalis eiriktsarpalis added this to the Future milestone Jan 29, 2025
@bartonjs
Copy link
Member

bartonjs commented Feb 4, 2025

Video

  • Looks good as proposed
  • We raised the question of should it be "TryRemove" instead of "Remove", but left it as "Remove" to be consistent with the same overload pair on Dictionary`2.
namespace System.Runtime.CompilerServices;

public sealed partial class ConditionalWeakTable<TKey, TValue>
{
    public bool Remove(TKey key, [MaybeNullWhen(false)] out TValue value);
}

@bartonjs bartonjs added api-approved API was approved in API review, it can be implemented and removed api-ready-for-review API is ready for review, it is NOT ready for implementation labels Feb 4, 2025
@dotnet-policy-service dotnet-policy-service bot added the in-pr There is an active PR which will close this issue when it is merged label Feb 7, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api-approved API was approved in API review, it can be implemented area-System.Runtime.CompilerServices in-pr There is an active PR which will close this issue when it is merged
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants