RE: Future cancellation

I think the .NET disposal analogy is a good one. I don’t know how other runtimes handle it, but in .NET you would dispose of a resource (perhaps representing an in-progress asynchronous operation) by having the handle for that resource implement IDisposable, i.e. have a dispose() method. So I think if you wanted to do something similar with promises, you’d return a disposable handle alongside your promise (i.e. `return { promise, diposable }` or simply `{ promise, dispose }`). You can also layer that on top of the promise (i.e. `promise.dispose = () => { .. }; return promise;`).

From: Kevin Gadd []
Sent: Wednesday, May 1, 2013 00:35
To: Domenic Denicola
Cc: Jonas Sicking; Ron Buckton;; es-discuss
Subject: Re: Future cancellation

To be honest, I haven't yet seen an explanation of why 'I no longer have any need for the contents of this future' is not tied to the underlying semantics of a future. Where else would it go? I agree with you that complicating a primitive in order to support a small subset of use cases is undesirable, and it does seem like perhaps end-user subclassing of futures/promises addresses all these use cases. But it is troubling to me to consistently see real use cases dismissed as somehow unworthy of consideration because they do not meet some unspecified semantic bar.
And to restate some points that have cropped up in the thread multiple times so far, since they are relevant to your arguments:
Future cancellation is not the same as task cancellation; it is different. I would agree with any suggestion that using the names 'cancel' or 'abort' probably leads people to assume that they are the same. I prefer the term 'disposal' but that is perhaps overly .NETty and implies things that do not apply to JS.
Layering disposal onto a promise from the outside is fine, but requires that all consumers of an API have prior knowledge of the way the API is implemented; that is, the API author has to expose disposal beforehand (even if it is not used) and the consumer has to know that it is needed. This exposes whether or not disposal is *actually used* by an implementation when it should be an implementation detail. Much like how - to pick an arbitrary example - finally blocks in a generator should run if you enumerate the generator with for-of, it is desirable to have a universal way to indicate that a future's value is unneeded by a single consumer such that any given API implementer can extend their implementation seamlessly to abort operations that are no longer needed. This allows significant changes to the backend of an operation (caching, batching, etc) without changing the public API. (Note that you can probably address this with a Future subclass instead of baking disposal into Future itself, or by exposing some sort of public function that you can call on a future to indicate that you are done with it and making that function a no-op for non-disposable futures. I don't have a strong opinion).

I'm fine with cancellation and progress being nuked from futures for conceptual purity; simpler is probably better. But if you're going to kill them, you should do it based on sound reasoning, otherwise they're just going to keep cropping up again and again because people want them and will probably not accept a justification that seems based on a misunderstanding of their arguments.
Given the choice between explicitly not specifying disposal, and specifying an 'encouraged way to do it' (i.e. via subclassing), I would also lean towards the latter. That is, if you're going to say 'we don't need to spec disposal', by demonstrating an incredibly easy way to do it via subclassing, you address any arguments that it must be built into the language or into DOM futures, and you demonstrate a pattern that is expected to work based on the current spec.


On Tue, Apr 30, 2013 at 9:25 PM, Domenic Denicola <<>> wrote:
From:<> [<>] On Behalf Of Jonas Sicking

> It isn't actually surprising that the same issues arise. ProgressFuture basically delivers progress about an "operation" rather than a "result".
I agree. I think both progress and cancellation (of underlying operations) are attractive nuisances. They seem like they fit in well with the model, and would be useful for certain use cases. But they are actually very different, and not tied to the underling promise semantics at all—which are of a first class value representing a promised "result," as you put it, not representing an ongoing "operation."

I lean toward not specifying or including them at all. Although you can try to stuff them naively into the promise semantics, you end up needing to complicate the conceptual model in order to make them behave as you wish. As you point out, this is clearly visible with the various combinators. But it's also visible in basic semantic questions that arise: e.g. downward progress propagation/transformation, or the role of throwing inside a progress handler, or upward cancellation progagation/reaction, or downward cancellation forking, or the role of rejections in cancellation. You soon realize that you're trying to smush in semantics where they don't belong.

In other words, separate abstractions for cancellation or progress, unrelated to promises, seem best.
es-discuss mailing list<>

Received on Wednesday, 1 May 2013 05:02:18 UTC