News for hackers. Stuff that matters.
Re:Cancelable Promises: Why was this proposal withdrawn? by cwmma on Monday December 19, 2016 @07:57AM (#13211096)
Promises have always been extremely contentious in JS for a couple reasons and Domenic has had the patience of a saint getting the original proposal through so it's totally understandable that he might not want to deal with this anymore especially if people in his org are against it.

There were a couple reasons the original promises were so contentious to standardize.

- Monads: there was a very vocal faction on TC-39 that really wanted a Promises to be monadic and very much emphasized mathematical purity over usefulness and any attempt to discuss things tended to get side tracked into a discussion about monads, see brouhaha over Promise.cast [1].

- Error handling: Promises have a bit of a footgun where by default they can swallow errors unless you explicitly add a listener for them. As you can theoretically add an error listener latter on all other options had downsides (not always obvious to advocates) leading to a lot of arguing, must of it after things had shipped and realistically couldn't be changed. Fixed by platforms and libraries agreeing on a standardization of uncaught promise events [2].

- Just an absurd amount of bike shedding probably the 2nd most bike shedded feature of the spec (behind modules).

So cancelable promises reignite all the old debates plus there's no obvious right way to do it, like should it be a 3rd state which could cause compatibility issues and would add complexity, or should cancellations just be a sort of forced rejection, which would be a lot more backwards compatibility but with less features.

Additionally there is a bizarre meme that somehow observables (think event emitters restricted to a single event or synchronous streams that don't handle back pressure) are a replacement for promises or are a better fit for async tasks they should be used instead.

edit: patients => patience

1. https://esdiscuss.org/topic/promise-cast-and-promise-resolve

2. https://gist.github.com/benjamingr/0237932cee84712951a2

Re:Cancelable Promises: Why was this proposal withdrawn? by spion on Monday December 19, 2016 @09:33AM (#13211587)
The problem wasn't usefulness or purity, it was that the community already standardised on a certain behaviour of promises that was not monadic. The only way to make promises monadic was to therefore not standardise "promises" at all.

At that time, monadic tasks were basically unheard of in the community. By the very nature of the monad laws, they cannot have side-effects, so they cannot be eager. This means that a user "running" an operation would observe nothing until they subscribe to it. In an imperative language like JS, this is confusing for users, and arguably not worth the breakage of the existing promise ecosystem.

Another nice property of Promises is that they can be implemented in a way that doesn't cause stack overflow for endeless recursion (and additionally, in some cases we can get "tail recursion"). This might be doable with lazy tasks too - not entirely sure. See https://github.com/paf31/purescript-safely

On the other hand, monadic tasks make many other things easier, like

* cancellation (just unsubscribe),

* synchronous error propagation, so no issues with error swallowing and perhaps no post-mortem issues in node. Nothing runs before the subscription, so at the point the side effects are running, we already know whether there is an error handler. Effectively the `done` method would've been the eqiuivalent of `subscribe`, and mandatory

* defining parallel, sequential or limited-concurrency execution order after the tasks have been created

Re:Cancelable Promises: Why was this proposal withdrawn? by zeahfj on Monday December 19, 2016 @11:08AM (#13212288)
> By the very nature of the monad laws, they cannot have side-effects, so they cannot be eager.

I'm pretty sure monads can have side effects and be eager. It's just that not everything will be captured by the type signature. AFAIK this does not prevent it from being a monad. You can have monads without any type signature. Also, AFAIK the eagerness is a requirement due to the potential for errors changing program flow that is not captured by the type signature. But AFAIK this does not prevent it from being a monad.

AFAIK monads only have to conform to the monad laws, bind and return.

I'd like to know if I'm wrong because I'm concerned with the conflation of monads and language features of haskell. Specifically we can benefit from monadic composition without making javascript into haskell. I think Erik Meijer has been rather damaging in this regard. I know I'm in the minority so I'd like to be proven wrong so I can come join the party :)

Re:Cancelable Promises: Why was this proposal withdrawn? by SomeStupidPoint on Monday December 19, 2016 @11:55AM (#13212782)
IO is a monad in Haskell, right?

I mean, we can talk about how it's pure in the sense that it just lifts other things in to being tied to IO programs, and it's our evaluation of them that causes mutation, but that's pedantic even to me and seems to miss the point.

That sense of purity isn't what most people mean or are concerned by.

Re:Cancelable Promises: Why was this proposal withdrawn? by Guvante on Monday December 19, 2016 @01:15PM (#13213537)
IO a is short for roughly World -> (a, World) and is thus computationally pure. You cannot figure out what happens to the World in between but you don't need to, thus the side effects "don't exist" from a analysis standpoint.

However IO follows all of the Monadic laws, I believe the comments about side effects are focusing on the side effects that show through when you try and apply the monadic laws to promises.

Re:Cancelable Promises: Why was this proposal withdrawn? by spion on Monday December 19, 2016 @02:37PM (#13214331)
The "world" equivalence is not a useful way to think about it. A more useful description would be a tuple that contains two items, the first one being the description of the action to execute, and the second one being the function that will be called with the value retrieved with the action executed.

So in JS notation:

  { action: {type: 'readFile', fileName: f}, next: content => mkPrintAction(content) }
Re:Cancelable Promises: Why was this proposal withdrawn? by wyager on Monday December 19, 2016 @06:54PM (#13216115)
> The "world" equivalence is not a useful way to think about it.

Regardless of your opinion on the matter, that's how it's actually implemented. IO is roughly equivalent to "State RealWorld#" with some extra strictness/unboxing stuff.

What you're talking about is basically the free monad over the (Request, Response -> a) functor. That would probably work, but be less performant and harder to extend.

IO is nice because it's really easy to safely integrate with FFI calls. I don't think you could easily do the same with your proposal.

Re:Cancelable Promises: Why was this proposal withdrawn? by spion on Tuesday December 20, 2016 @05:32AM (#13218759)
Its just that when you mention this, the assumption is that "World" is the state of the world. Which is not true, since world is just a token to impose ordering of execution in a lazy language, but its a fake state token since its not present at run time... and that complicates the explanation further.

The interpreter is simpler and easy to implement in any language too.

Re:Cancelable Promises: Why was this proposal withdrawn? by wyager on Tuesday December 20, 2016 @01:02PM (#13222250)
That's true, the compiler does optimize away the explicit dependency on the world. But it still makes sense; when you call "print", it returns a "new world" that is the state of the world after printing. You can't inspect the state of the world, so it doesn't really matter whether it's just a token or an actual description of the universe. The behavior is indistinguishable either way.
Re:Cancelable Promises: Why was this proposal withdrawn? by spion on Wednesday December 21, 2016 @06:46AM (#13228398)
That assumes there is only one program running in the world. Its simply not clear what the "world" type means. Its a bad name. I'd rather go ahead and explain it as a token.
Re:Cancelable Promises: Why was this proposal withdrawn? by wyager on Wednesday December 21, 2016 @03:08PM (#13232194)
I don't see why it assumes there is only one program. If the world value is impossible to inspect (which it is), you can assign whatever semantics you like to it.

If you look at the generated core code, it's important to notice that it's not the same "token" being passed around everywhere. Each IO action returns a new token, which could be a different value from the old token. (Again, this is entirely theoretical, as the token/world state doesn't exist in the binary.)

Re:Cancelable Promises: Why was this proposal withdrawn? by spion on Wednesday December 21, 2016 @08:23PM (#13234052)
Ok, I'll put it this way:

Saying

> when you call "print", it returns a "new world" that is the state of the world after printing

makes no sense, since the word "state of the world" will be interpreted completely differently by the receiver of the explanation. State of the world = a large state object with lots of fields describing every single thing in some "World" (what world: program world? computer world? network world? all the world?). Thats what people hear.

The name of the type is horrible, and the world-passing intuition is also horrible. "Token" would've been much better, but its still not clear how to implement or why its even necessary (in a non-lazy language)

On the other hand, a tuple representing the current action and the function that will return the next action (or nil) is fairly clear, easy to implement an interpreter for, the pure/nonpure distinction becomes obvious (the runtime interpreter is the impure part), and laziness doesn't even need to get into the mix.

oh, and also regarding FFI: {type: 'FFICall', fn: string, arguments: [...]}

Re:Cancelable Promises: Why was this proposal withdrawn? by wyager on Thursday December 22, 2016 @06:28PM (#13241401)
That's a fair argument. People might get caught up on thinking that the world object actually has to contain a description of the world.

> {type: 'FFICall', fn: string, arguments: [...]}

I agree that this is simpler to understand, but it's no good in practice. It's obviously not type safe, and you still have to bake support into the interpreter/runtime for whatever your string value is. It's also effectively impossible to inline/optimize away. Which, again, is probably why it's done using "State RealWorld#" in GHC.

I would like to reiterate that however RealWorld# happens to be defined, the way its use is enforced in GHC is the exact same as if it did actually contain a description of the entire universe. You just aren't allowed to look at it. But, you are correct, this is more confusing than a request/response free monad.

Re:Cancelable Promises: Why was this proposal withdrawn? by anewhnaccount on Monday December 19, 2016 @07:18PM (#13216254)
Honestly I've always just thought of Monads as-in Haskell as a tricky way of sequencing in the presence of lazy evaluation. Looked at this way, the "trick" is to make a data dependency between each step in the form of an argument. Since Haskell names must be bound before they're read this means we can guarantee the order in which the steps are evaluated relative to one another. Then the whole thing is wrapped up in a data structure (this latter part seems to be what people normally focus on).
Re:Cancelable Promises: Why was this proposal withdrawn? by SomeStupidPoint on Monday December 19, 2016 @10:46PM (#13217304)
This is a late reply, but your abstraction is leaky: World might mutate during an IO operation in a way which impacts the outcome. So the (a, World) result isnt fully deterministic from World. Even if you make each IO operation atomic, a chain of IO is still impure because the final (a, World) result depends on mutations introduced during execution.

The lift to constructing an IO program from a Haskell type is pure, but the execution of that program to generate a value or effect on the system is not.

So Haskell is "pure" when it comes to IO, but not in the way anyone except overly pedantic people mean the term.

Re:Cancelable Promises: Why was this proposal withdrawn? by Guvante on Wednesday December 21, 2016 @04:29PM (#13232792)
World cannot be inspected in any meaningful way in this paradigm so it is fully deterministic because the differences aren't important.

> So the (a, World) result isnt fully deterministic from World. Even if you make each IO operation atomic, a chain of IO is still impure because the final (a, World) result depends on mutations introduced during execution.

It is fully deterministic from World but you cannot possibly describe a World so you can't supply it nor replicate it.

> So Haskell is "pure" when it comes to IO, but not in the way anyone except overly pedantic people mean the term.

You can't create a World so it is pedantic in that fashion but you are able to think of the functions as pure otherwise making integration easier.

A simple example is that IO happens in the correct order in Haskell because of the evaluation order not due to some external construct ensuring that lazy doesn't bite you.

Re:Cancelable Promises: Why was this proposal withdrawn? by spion on Sunday December 25, 2016 @10:34AM (#13254367)
Which only goes to show that you can't apply real world reasoning to explain an academic concept. In this purely theoretical concept, World (which cannot be inspected) does contain the entirety of the world, including all other actions running in parallel, the current time and the state of every atom in the universe. So given the exact same state of the universe and assuming purely deterministic laws governing it (or the state of the world containing the future of the world too), yes, the action will produce the exact same output, because all other actions running in parallel or the things that will lead to the future actions are also part of that input World state.

Thats my best attempt, and it still sucks! I bet someone will start wondering about the uncertainty principle there... So lets just use a free monad or thunks in a strict language

  function pureAction() {
    return function() { return impureAction(); }
  }

  function chain(pureAction, fnReturningOtherAction) {
    return function() {
      var impureResult = pureAction();
      var newAction = fnReturningOtherAction(impureResult);
      return newAction();
    }
  }


  function interpreter(mainAction) { return mainAction(); }

Everything is pure, since all the functions don't do anything but return thunks for the interpreter to run. Except the interpreter which actually runs those. This isn't even a theoretical explanation - its exactly how PureScript's Eff works.
Re:Cancelable Promises: Why was this proposal withdrawn? by zeahfj on Monday December 19, 2016 @01:26PM (#13213650)
Would it be fair to say that the IO Monad get passed along implicitly with the other Monads in an eager evaluating system? Would this make it a stack? Just one that's not represented or enforced by the type system.
Re:Cancelable Promises: Why was this proposal withdrawn? by Guvante on Thursday December 22, 2016 @08:51PM (#13242160)
I dunno, so much of the IO Monad is specific to Haskell and lazy evaluation. Generally I think of it as Haskell's quirky way of handling the real world in a pure lazy mathematical construct and not something fundamental.
Re:Cancelable Promises: Why was this proposal withdrawn? by lmm on Monday December 19, 2016 @12:05PM (#13212875)
The monad laws are defined in terms of equivalence of values. So if your promise is not a value then you can't even begin to talk about whether it conforms to the monad laws or not. If `Promise(someWebRequest())` starts performing the web request immediately then we can't talk about it as a value (or rather, in order to regard it as a value we have to elide some aspects of it that are actually quite crucial, such as the web request being performed).
Re:Cancelable Promises: Why was this proposal withdrawn? by tpetricek on Monday December 19, 2016 @12:23PM (#13213057)
Perhaps you're a minority, but you're not alone - I too think that the usual narratives around monads (and many other theoretical CS concepts) are quite harmful. Do not get me wrong - they can all be useful, but not when they are conflated with many other things that some people like to have together with monads.
Re:Cancelable Promises: Why was this proposal withdrawn? by spion on Monday December 19, 2016 @01:08PM (#13213485)
Well lets see if the first law holds. It says

Promise.resolve(a).then(f) == f(a)

Immediately this is not true, since `f` can throw or return a non-promise.

But lets say we restrict the type of f so that it can only return promises. Once again, the statement is not correct - the executed side effect is not the same. The left side will execute with one tick delay of the microtask queue, while on the right side the side effect executes immediately. So the side effects are not equivalent. If we write `f(a); f(b);` and `Promise.resolve(a).then(f); f(b);`, in the first case the side effects will start in order; in the second case, they will start in the reverse order. If we cannot replace one side of equal sign in the law with the other and have things run exactly the same, that means equational reasoning doesnt work [1], and the law doesn't apply.

In theory you could probably make monads with side-effects, but promises don't satisfy the laws. Its much easier if the monad only represents side effects but doesn't actually run them. You can think of them as redux action objects - they don't actually do anything once they are created. They only represent the side effect that will be run. For example, their internal representation could be {action: 'readFile', argument: 'path/to/file.json'}. ($)

You can construct actions from other actions by chaining them with a function that will take the result from the action and produce a new action object. Those would be derived actions. You can think of them as cons cells - they have the original action, and the function that produces a new action. Example representation: {originalAction: {action: 'readFile', argument: 'path/to/file.json'}, nextActionFunction: result => printLine(result)}

Finally, you pass the action to the "interpreter". The interpreter reads each action, runs the originalAction part of the cons cell, then produces a new actioin using the function in the nextActionFunction cell. It repeats that until it gets to an empty nextActionFunction cell.

($) Anoter practical representation for compile-to-js languages would be to use a thunk for the base (original) action. A thunk is a function without arguments, that when run, will produce a side-effect and return a value. The interpreter would then be simply a thunk runner. An async thunk can also be used, and thats a thunk that takes a callback that will be called with the eventual value. Still, we're only producing values without creating side effects: the laws are much easier to uphold.

[1]: http://www.haskellforall.com/2013/12/equational-reasoning.ht...

Re:Cancelable Promises: Why was this proposal withdrawn? by azernik on Monday December 19, 2016 @05:43PM (#13215676)
The first one is a pretty nitpicking one, IMO; all that's happened is that then/fmap and map have been collapsed into a single function that dynamically dispatches on the type of the returned value to decide which behavior to execute. More of an ergonomic convenience for programmers who don't quite grasp the distinction.

Edit: And with regard to the side effect ordering question -monads are only well-known defined for pure functions anyway! By that standard, any Scala code using non-pure functions is also not using a monad. This I inevitable in a language that does not enforce purity, which is basically every widely-adopted one that's not Haskell. A definition of "support" that excludes implementations that allow (but do not require) non-pure functions is not a very useful definition.

Re:Cancelable Promises: Why was this proposal withdrawn? by spion on Tuesday December 20, 2016 @05:34AM (#13218764)
Thats not the issue here. Even if the functions themselves are pure (beyond the act of creating a promise), the strictness of promises together with their micro-task queue rule impose execution ordering that make them a non-monad. So its impossible to write your functions in a way that the laws hold.

And if you can't use the laws for equational reasoning, then what good is it whether its a "monad" or not anyway?

Re:Cancelable Promises: Why was this proposal withdrawn? by zeahfj on Monday December 19, 2016 @01:36PM (#13213734)
How would it be less of a Monad than the IO Monad? That's the part I'm not getting. It would make sense to me if neither were considered monads.
Re:Cancelable Promises: Why was this proposal withdrawn? by spion on Monday December 19, 2016 @02:32PM (#13214292)
If the monad laws don't hold, its not a monad. I demonstrated the first law not holding, therefore promises are not a monad.
Re:Cancelable Promises: Why was this proposal withdrawn? by staltz on Monday December 19, 2016 @09:21AM (#13211515)
Why do you say "bizarre meme"? Observables are not like event emitters. RxJS Subjects would fit that description. See http://stackoverflow.com/questions/25338930/reactive-program... and https://www.youtube.com/watch?v=uQ1zhJHclvs

Observables are just an API for any push system based on callbacks, to make it composable and lazy. Array.forEach uses callbacks, Promise.then uses callbacks, Node.js streams are consumed using callbacks. And observables can model those cases without losing their properties (e.g. Array.forEach is called synchronously).

Re:Cancelable Promises: Why was this proposal withdrawn? by bad_user on Monday December 19, 2016 @09:40AM (#13211636)
In fairness, while Observables look similar to Promises and while it seems that a Promise could inherit from an Observable (like the Single type is doing in RxJava), this is one of those real-world cases of inheritance gone terribly wrong.

The fact of the matter is Observables get used for different use-cases than Promises. And for the use-cases for which Promises end up being used Observables are broken.

For example Observable's flatMap operation is most likely not memory safe and so it cannot be used in a "tail recursion". This is because we have to wait on the "onComplete" event in order for resources to be de-allocated and that cannot happen before the last Observable emitted by the last "onNext" signals its own "onComplete". But tail-recursion is a primary use-case for a Promise type and so its "flatMap" needs to be memory safe.

I've thought long and hard about it btw, I even have a library that implements both a lazy Task abstraction and the Observable pattern: https://monix.io

I love observables obviously, but Observable isn't a substitute for a Promise and I hope we don't go down that road.

Re:Cancelable Promises: Why was this proposal withdrawn? by staltz on Monday December 19, 2016 @09:55AM (#13211733)
flatMap isn't memory safe but switchMap is, and it's often used for the type of request/response chaining that we do with Promise.then.

With pratical experience using Observables in production for any use case people normally use Promises, I disagree with you about not being a substitute, and specially about being "broken".

Re:Cancelable Promises: Why was this proposal withdrawn? by naasking on Monday December 19, 2016 @10:17AM (#13211887)
From the FRP literature, an observable can be viewed as a stream of promises, something like:

    { "value" : ..., "next" : new Promise(...) }
So it's basically a linked list of the current value, and the next value which is a promise for the same type of structure.
Re:Cancelable Promises: Why was this proposal withdrawn? by bad_user on Monday December 19, 2016 @02:49PM (#13214444)
An observable is definitely not a stream of promises, because an observable is push-based, while a stream of promises would be pull-based.

Big difference in performance, implementation and what operations are possible or not. Even if you add back-pressure in that protocol, it's still a big difference.

And yes, my point is that an observable is close to being a sort of superset of a promise, but not close enough.

Re:Cancelable Promises: Why was this proposal withdrawn? by naasking on Monday December 19, 2016 @04:36PM (#13215179)
> An observable is definitely not a stream of promises, because an observable is push-based, while a stream of promises would be pull-based.

Why would a stream of promises be pull-based? That seems like a pretty odd assumption to me.

Re:Cancelable Promises: Why was this proposal withdrawn? by cwmma on Monday December 19, 2016 @09:38AM (#13211623)
> Why do you say "bizarre meme"?

the bizarre meme is that they are 'replacements' for promises, they are really intended for (as you rightly put it) push streams which is a different, though occasionally overlapping, use case then promises.

Re:Cancelable Promises: Why was this proposal withdrawn? by staltz on Monday December 19, 2016 @09:56AM (#13211743)
I said push system, not push stream. Promises are a push system.
Re:Cancelable Promises: Why was this proposal withdrawn? by spion on Monday December 19, 2016 @10:15AM (#13211871)
If there was a specialized Observable that is guaranteed to only generate one value per subscription, and the API indicated this clearly by naming such an observable "Task" or "Future", I'd be all for it.

Otherwise, its like using Arrays or Lists instead of Maybe. Hope that clears up why its "bizarre", but if not, its because the contract is not restrictive enough.

Example: `let x:Observable<Row[]>`. Does this generate a single event with all the rows? Or does it do row batching? No idea. Can I consume both the same? Not really, depends on the use. e.g. if I want to sort the items, I'd have to implement merge sort for the second case.

Re:Cancelable Promises: Why was this proposal withdrawn? by staltz on Monday December 19, 2016 @09:03PM (#13216787)
> If there was a specialized Observable that is guaranteed to only generate one value per subscription, and the API indicated this clearly by naming such an observable "Task" or "Future", I'd be all for it.

Given any Observable `obs`, you can consume it with `obs.take(1).subscribe()` instead of `obs.subscribe()` and then you'll be sure it only generates one value per subscription.

But in practice the generation of multiple values in itself is rarely an issue to worry about. Often you just want to drop consecutive duplicates, there's an operator for that: `distinctUntilChanged`. You can also end an observable based on a timeout.

Multiple values emitted is a pseudo-problem, and often your programming becomes more powerful ("does more in less lines of code") by using that capability.

Re:Cancelable Promises: Why was this proposal withdrawn? by spion on Tuesday December 20, 2016 @05:39AM (#13218782)
Okay. Please replace all Maybe instances in your code with Arrays and let me know how that goes.
Re:Cancelable Promises: Why was this proposal withdrawn? by int_19h on Monday December 19, 2016 @06:51PM (#13216093)
I think the argument here was indeed to treat promises as a subset of observables, not replace them with observables. Just as option type is a subset of collections that can have at most 1 element (but all operations that apply to any other collection, like say "map", still make sense for it).
Re:Cancelable Promises: Why was this proposal withdrawn? by koolba on Monday December 19, 2016 @08:07AM (#13211111)
> Promises have always been extremely contentious in JS for a couple reasons and Domenic has had the patients of a saint getting the original proposal through so it's totally understandable that he might not want to deal with this anymore especially if people in his org are against it.

I know this is probably a typo (patients => patience) but that spelling seems to work as well.

> So cancelable promises reignite all the old debates plus there's no obvious right way to do it, like should it be a 3rd state which could cause compatibility issues and would add complexity, or should cancellations just be a sort of forced rejection, which would be a lot more backwards compatibility but with less features.

IMHO neither as cancelability isn't a common requirement. People that need it tend to have more complex requirements and end up tying the cancellation to other chains of logic anyway. Also, unlike say catching an error, you generally want all cancellation handlers to fire rather than just the first one (like with errors).

Re:Cancelable Promises: Why was this proposal withdrawn? by zbjornson on Monday December 19, 2016 @11:46AM (#13212668)
It's fairly common to cancel an HTTP request. The new fetch API doesn't let you cancel a request as a consequence of this shortcoming of promises, while XMLHttpRequest does.
Re:Cancelable Promises: Why was this proposal withdrawn? by webartisan on Monday December 19, 2016 @08:33PM (#13216596)
I think cancelling HTTP requests is quite a useful in some scenarios. Eg 1) Say you're fetching heavy json/binary data on an user action, and before data arrives, he changes his action. Not only do ypu download all of the extra data, but the fetch for the next action is slowed down like hell.

Not sure, but does this mean that I can't cancel a heavy file upload if a user changes his mind?

Re:Cancelable Promises: Why was this proposal withdrawn? by pacaro on Monday December 19, 2016 @12:43PM (#13213245)
Herein lies the rub.

So I cancel my GET request, all is fine with the world. I cancel my POST, and now I have no idea at which layer it was cancelled, if at all. Certainly the cancel doesn't propagate to the server.

I've used cancellation in C# and agree that it's super useful, but it's not a panacea and has to be handled thoughtfully. JS can manage without it IMHO

Re:Cancelable Promises: Why was this proposal withdrawn? by Klathmon on Monday December 19, 2016 @01:25PM (#13213637)
The counter-argument to that is what happens when you make a GET request for a 1gb file? Or you POST a 1gb upload?

Canceling them is now a big deal if it's needed.

Personally, I think they could be handled by the WebStreams API, so when you want to "cancel" a download or upload, you just throw in the function which is consuming or creating the actual data which will reject the promise entirely.

However only ReadableStreams are available in some browsers right now, and WritableStreams are still a bit away AFAIK, so it's not possible to do that right now with promises, but i don't think that warrants adding even more features to a language which will most likely never be removed.

Re:Cancelable Promises: Why was this proposal withdrawn? by pacaro on Monday December 19, 2016 @02:11PM (#13214082)
I agree. If you're handling objects of that size in single requests, then you're already in footgun territory. Step carefully.
Re:Cancelable Promises: Why was this proposal withdrawn? by int_19h on Monday December 19, 2016 @06:53PM (#13216109)
Cancellation is a high-level expression of intent that you no longer care about the result of the operation.

Due to the very nature of asynchronous operations, it is, in general, impossible to even determine which layer will ultimately handle that request (e.g. in your example, whether the POST won't happen, or it'll be aborted, or it's already completed), much less how it'll be handled.

The assumption is that all layers will do their best effort (defined vaguely in a "common sense" way) to service that request.

That is a very useful abstraction to have, and I don't see why JS is special in that regard.

Re:Cancelable Promises: Why was this proposal withdrawn? by Manishearth on Monday December 19, 2016 @01:32PM (#13213696)
I mean, this isn't new. When you make a POST request in JS a bad network may mean that it gets delivered but errors out on your end. You need to code your application to be robust to this anyway.
Re:Cancelable Promises: Why was this proposal withdrawn? by pacaro on Monday December 19, 2016 @02:09PM (#13214058)
This. Absolutely.

Those applications that already aren't robust to this (I sadly assume that is most) aren't going to be helped by cancellation

Re:Cancelable Promises: Why was this proposal withdrawn? by cwmma on Monday December 19, 2016 @08:19AM (#13211174)
fixed the spelling and you're right it's not a super common requirement, but it comes up in context of designing APIs to use promises, and if you are trying to add promises to an API that is cancelable, you'd want some way to express that.
Re:Cancelable Promises: Why was this proposal withdrawn? by Rapzid on Monday December 19, 2016 @08:49AM (#13211326)
Do you have any idea what the current direction is(if any?) that they are moving in? I'm mostly familiar with the use of tokens; Golang using Context and C# using CancelationToken.

I currently utilize cancellation tokens myself in nodejs(TypeScript) when creating libraries or wrapping the stdlib event/stream based stuff.

Re:Cancelable Promises: Why was this proposal withdrawn? by cwmma on Monday December 19, 2016 @10:08AM (#13211809)
With this canceled there is no official direction, and any further movement will likely be based on what is decided in the community.
Re:Cancelable Promises: Why was this proposal withdrawn? by jrochkind1 on Monday December 19, 2016 @12:33PM (#13213141)
> So cancelable promises reignite all the old debates plus there's no obvious right way to do it, like should it be a 3rd state which could cause compatibility issues…

It seems obvious to me that the 'right' way to do it is a cancelled promise is in the error state, with the error object just being a new type of error CancelledPromise or something.

But I guess once you start getting into it, this becomes less obvious?

Re:Cancelable Promises: Why was this proposal withdrawn? by ralfn on Tuesday December 20, 2016 @06:24AM (#13218945)
No, the right way is to fix the fetch() api to not return a promise and reflect on why the system was so broken that fetch() api was released with such an obvious flaw.

Because Promises don't need to be cancellable. This has nothing to do with promises. Fetch requests need to be cancellable. But they, in all their wisdom, decided that the fetch API returns a promise. So now promises need to become whatever the hell the fetch API actually needs to return.

You would almost think design by committee is fundamentally flawed, and design by community even more flawed.

Because the edge cases are never obvious. For every new feature the question shouldn't be "do i make 99 programmers 1% happier?", but do i make 1 programmer cry upto the point where they would stab my eyes out if they could?

We've all been that 1 programmer, and yes, i would if i could. It's a clusterfuck of bike shedding. Most new ES2016 have details that haven't been though through and will end up being hated on the same level as '==' and 'NaN'.

The dev-leads of the different javascript engines should not just be able to veto. They should be able to veto people out of the room, out of the debate. And we should celebrate it every time they take advantage of that power. Or just give up on Javscript all together and just let the rot fester.

Re:Cancelable Promises: Why was this proposal withdrawn? by jrochkind1 on Tuesday December 20, 2016 @09:06AM (#13219855)
I think fetch definitely needs to (at least as an option) offer some kind of async API built-in without adding another dependency. Async is likely the most common use case in the browser. I have not been displeased with the fetch->promise API, it works well for me, and is definitely a lot more convenient than XMLHttpRequest. Which part do you disagree with from your experience?
Re:Cancelable Promises: Why was this proposal withdrawn? by ralfn on Tuesday December 20, 2016 @10:32AM (#13220646)
I love the fetch-api as well, but it doesn't allow for one to cancel the request. Which is why people want to change Promises in the first place. Because the committee in all its wisdom has specified that the fetch-api returns a promise. So the only way to make the requests of the fetch-api cancellable is to change the return type of the fetch-api. But that has been standardized to be a Promise. So now they want to change Promises to be whatever the hell they need from the fetch-api.

Do i need to cancel requests? Not really. But not being able to cancel requests is now driving a shitstorm of short-sighted proposals to mutate the Promise contract into some sort of 'whatever the hell the fetch-api really needs reply object'.

Re:Cancelable Promises: Why was this proposal withdrawn? by jrochkind1 on Tuesday December 20, 2016 @10:59AM (#13220943)
There's probably a (hypothetical API) way to get a _fetch_ to be cancellable, even though it returns a promise, without altering the API of general promise. Some way to get a reference to the request going on and cancel it, which would result in the promise failing (assuming it hadn't completed yet) with a FetchCancelledError or something. One could certainly imagine building such an API if one were polyfilling fetch onself built on XMLHTTPRequest (which can be cancelled).

I won't bother trying to think it through though cause it's clearly pointless except as an intellectual exersize!

I actually like that fetch returns a Promise, I find it convenient, I don't think it was a bad choice at all. To make Promise part of ES6 as a general-purpose async primitive, and to make Fetch return one. I also see how it would be nice to allow fetches to be cancelled -- although I'm not sure I've ever needed/wanted to do that, I could see how I might in the future.

It is boggling that a bunch of smart interested people haven't been able to figure out _some_ solution to this.

Re:Cancelable Promises: Why was this proposal withdrawn? by cwmma on Tuesday December 20, 2016 @08:20AM (#13219515)
> The dev-leads of the different javascript engines should not just be able to veto. They should be able to veto people out of the room, out of the debate. And we should celebrate it every time they take advantage of that power. Or just give up on Javscript all together and just let the rot fester.

this would ironically tend to be applied to people like you

Re:Cancelable Promises: Why was this proposal withdrawn? by ralfn on Tuesday December 20, 2016 @10:24AM (#13220552)
No irony :) I don't think i should be in that room. I know enough to know how little i know. I also know enough to recognize a naive short sighted proposal such as 'cancellable promises'.

That doesn't mean it should be me dismissing that feature. But i am very much smiling that the people that should be in that room, did dismiss it.

Re:Cancelable Promises: Why was this proposal withdrawn? by cwmma on Monday December 19, 2016 @01:17PM (#13213553)
Bingo, it turns the same thing wasn't wasn't obvious to everyone
Re:Cancelable Promises: Why was this proposal withdrawn? by jrochkind1 on Monday December 19, 2016 @09:02PM (#13216777)
weird. it would be interesting to read more of the debate/discussion, is it actually avail anywhere?
Re:Cancelable Promises: Why was this proposal withdrawn? by Nekorosu on Monday December 19, 2016 @09:01AM (#13211389)
> Monads: there was a very vocal faction on TC-39 that really wanted a Promises to be monadic and very much emphasized mathematical purity over usefulness

I don't think this was the case. The main argument of FP side was having more composability built into the core of the language.

Re:Cancelable Promises: Why was this proposal withdrawn? by indolering on Monday December 19, 2016 @06:38PM (#13216005)
While it's great that they were so nice, they are unable to effectively moderate GitHub and ESDiscuss. One ticket for the private member proposal had 600+ comments, some of them crazy stream-of-consciousness posts that should have been shut down.

Dealing with this volume of input requires aggressive moderation, community participation guidelines, and canonical explanations of the decision making process.

Re:Cancelable Promises: Why was this proposal withdrawn? by RodericDay on Monday December 19, 2016 @08:10AM (#13211118)
> Promises have a bit of a footgun where by default they can swallow errors unless you explicitly add a listener for them.

"a bit of a footgun" is such a huge understatement. Now that I know about this, I'm skeptical too.

Re:Cancelable Promises: Why was this proposal withdrawn? by cwmma on Monday December 19, 2016 @08:16AM (#13211159)
and you've missed the last part of that paragraph where I mention unhandledRejection events becoming a defacto standard which straddles a nice line between avoiding false positives (error listener attached latter in the program) and errors going into a black hole
Re:Cancelable Promises: Why was this proposal withdrawn? by Rapzid on Monday December 19, 2016 @08:43AM (#13211294)
Not sure if that's gone in yet so I've continued using Bluebird for my stuff. You can(and should!) create a global handler for unhandled rejections. It's almost always a bad sign if you get one.
Re:Cancelable Promises: Why was this proposal withdrawn? by RodericDay on Monday December 19, 2016 @08:46AM (#13211314)
Then don't call them "a bit of a footgun". It's a huge issue, in the process of being maybe fixed, and underplaying it to argue your side does not help matters.
Re:Cancelable Promises: Why was this proposal withdrawn? by spion on Monday December 19, 2016 @08:57AM (#13211368)
Its already fixed. Thats why it was just "a bit" of a footgun i.e. not unfixable.
Re:Cancelable Promises: Why was this proposal withdrawn? by TheAceOfHearts on Monday December 19, 2016 @09:15AM (#13211472)
Promises work fine in some cases, but absolutely I hate how exceptions and errors are grouped into the same bucket. Oh, you're handling 4XX responses as errors? Well, now you get exceptions there as well, good luck!

e.g. If I'm sending some data over the network, I want runtime errors to cause activity to be aborted and logged. But if I get a 429, I'll want to wait and retry.

Re:Cancelable Promises: Why was this proposal withdrawn? by spion on Monday December 19, 2016 @09:20AM (#13211511)
Which is why you write a catch combinator to filter out only the errors you want

  function ifErr(predicate, handler) {
    return e => { if (predicate(e)) return handler(e); throw e; }
  }

  function codeIs(n) { return e => e.code == n }

  promise.catch(ifErr(codeIs(429), e => handle error here))
Re:Cancelable Promises: Why was this proposal withdrawn? by paulddraper on Monday December 19, 2016 @10:32AM (#13211981)
What treats a 429 response as an error?

XMLHttpRequest doesn't use promises, and the Fetch API treats all HTTP responses -- including 429 -- as success.

I think you have a problem with a library.

Re:Cancelable Promises: Why was this proposal withdrawn? by TheAceOfHearts on Monday December 19, 2016 @02:47PM (#13214415)
Yeah, I never said otherwise. I had jQuery.ajax [0] in mind when writing that. If I recall correctly, it rejects the promise when you get a 4XX. I haven't used it since a few years now, but I still see people handling responses incorrectly with other wrapper libs.

[0] https://api.jquery.com/jquery.ajax/

Re:Cancelable Promises: Why was this proposal withdrawn? by paulddraper on Monday December 19, 2016 @04:59PM (#13215350)
Sorry, meant to reply to parent....

But yeah...one of the several reasons I much prefer Fetch API/polyfill to $.ajax.

Re:Cancelable Promises: Why was this proposal withdrawn? by y4mi on Monday December 19, 2016 @11:00AM (#13212203)
no, libraries should not throw exceptions if they get a http response. that is a perfect example where the programmer has to roll his own, because this is entirely situational.

the pseudo-code example of the grandparent seems to me to implement a) detecting the http code, b) throwing an exception and finally c) handling this except.

Re:Cancelable Promises: Why was this proposal withdrawn? by vinylkey on Monday December 19, 2016 @11:52AM (#13212748)
See superagent where anything that's not a 2xx is treated as an error (https://github.com/visionmedia/superagent/issues/283)
Re:Cancelable Promises: Why was this proposal withdrawn? by spion on Monday December 19, 2016 @11:03AM (#13212238)
Which pseudo code are you referring to?

Exceptions being for "exceptional" circumstances is a popular misconception. Exceptions are for "an upper layer to handle". You can use them for any alternative values you wish to propagate to the upper layer.

Re:Cancelable Promises: Why was this proposal withdrawn? by paulddraper on Monday December 19, 2016 @11:48AM (#13212706)
> Exceptions are for "an upper layer to handle".

So are return values :) The difference is that return value is for the next immediate layer; an exception is for some layer, but I don't know what.

IMO your HTTP layer should not be throwing exceptions based on status code. The layer above that should.

Re:Cancelable Promises: Why was this proposal withdrawn? by spion on Monday December 19, 2016 @01:20PM (#13213589)
Oh ok. Its not pseudocode, the combinators work :)

I would put it the other way around. The http layer should not decide that the layer immediately above it must be the one to handle all its errors. It should also be the one that defines the default (success) case and the error case, since those are defined by the HTTP protocol.

Re:Cancelable Promises: Why was this proposal withdrawn? by TheAceOfHearts on Monday December 19, 2016 @07:26PM (#13216300)
I didn't realize this was a point of contention. I had jQuery.ajax in mind when I wrote this, if I recall correctly they reject the promise when it doesn't receive a 2XX.

For comparison, the new fetch API resolves to a response which can have any status code.

Re:Cancelable Promises: Why was this proposal withdrawn? by bad_user on Monday December 19, 2016 @09:22AM (#13211525)
> Monads: there was a very vocal faction on TC-39 that really wanted a Promises to be monadic and very much emphasized mathematical purity over usefulness and any attempt to discuss things tended to get side tracked into a discussion about monads, see brouhaha over Promise.cast

Monads are about usefulness, because a type being monadic means there is a bind/flatMap operation you can rely on to have a set of laws. So a Promise being Monadic means that it is lawful and more composable. And it is especially relevant in the context of a Future/Promise. Aren't you tired of Javascript Future/Promise implementations that are broken?

Like, please learn about the concept.

Re:Cancelable Promises: Why was this proposal withdrawn? by kaishiro on Monday December 19, 2016 @09:34AM (#13211594)
This is one of the most ironic comments I've ever read on HN, right down to your final knife twist.
Re:Cancelable Promises: Why was this proposal withdrawn? by depr on Monday December 19, 2016 @09:48PM (#13217017)
I don't get the value of composability and refuse to learn, and "monad" and "laws" sound like math which I don't want to understand. So instead of attempting to comprehend what this is about I'm just going to make fun of you in a comment.
Re:Cancelable Promises: Why was this proposal withdrawn? by throwanem on Tuesday December 20, 2016 @06:07PM (#13225179)
I don't see a lot of point in making better programming concepts seem accessible, and "try to meet people where they are" sounds like populism which I don't want to understand. So instead of attempting to argue that there's value in the idea in a way that doesn't put people off with an implicit accusation of lazy ignorance, I'm just going to go with the implicit accusation of lazy ignorance.
Re:Cancelable Promises: Why was this proposal withdrawn? by throwanem on Monday December 19, 2016 @12:02PM (#13212832)
Like, yeah! It's just a monoid in the category of endofunctors. What's the problem?
Re:Cancelable Promises: Why was this proposal withdrawn? by jackmott on Monday December 19, 2016 @09:25AM (#13211540)
annnd there we go