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

Make it easier to safely hold a reference that can cancel an operation without holding the whole operation #217

Open
natebosch opened this issue May 4, 2022 · 1 comment
Labels
type-enhancement A request for a change that isn't a bug

Comments

@natebosch
Copy link
Member

A common pattern is to have a class that can hold callbacks which need to be triggered after a component or widget is disposed.

For instance Disposer: https://pub.dev/documentation/angular_components/latest/utils_disposer_disposer/Disposer/addFunction.html

If a tearoff of CancelableOperation.cancel is passed then the data returned through the operation will be held in memory for the lifetime of the disposer.

A safer pattern would null out a reference to the operation (and therefore the data) when it is complete so it doesn't get held longer than needed. We could consider adding an extension method or similar for this. We might even want to consider linting for this scenario, or even deprecating cancel() in favor of a safer alternative.

extension SafeCancel on CancelableOperation {
  void Function() get safeCancel {
    CancelableOperation? operation = this;
    whenComplete(() {
      operation = null;
    });
    return () {
      operation?.cancel();
    };
  }
}

@lrhn - WDYT?

@natebosch natebosch added the type-enhancement A request for a change that isn't a bug label May 4, 2022
@lrhn
Copy link
Member

lrhn commented May 9, 2022

It's a tricky problem

I was about to suggest using a Finalizer or weak reference, but the disposer actually do need to retain a reference to the object, even if it's the last reference in the world, if the object still needs to be disposed.

The disposer's cancel operation does not need to retain the result, though. When the cancel becomes a no-op, it doesn't need to retain anything.

So the design here could work. I don't like safeCancel. I can't explain to people why not use safeCancel every time, so it should just be cancel and be the first cancel you find.
Then it will also be weird if it's not a method.

I can't find a good rewrite with those constraints, not with the current interface (same object provides both the operation and the cancel, so as long as the outer object is alive, someone might get the operation result, but the cancel keeps the outer object alive.
The solution here is to not keep the object alive through the tear-off, by not making it a tear-off.

Not sure I'm happy with any approach here. Might even be better to just do nothing, and recommend users keep the life-time of their disposer as limited as possible.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type-enhancement A request for a change that isn't a bug
Projects
None yet
Development

No branches or pull requests

2 participants