00:12:26  <caiolima_>Jumping into the Promise cancelation as well. I tweeted with caitp last week and she presented me a point about "what happens with an await expression if a promise is canceled?". She convinced me that it has a big potential to break the new async code that is coming soon.
00:16:38  * Bakkotjoined
00:17:35  <ljharb>caiolima_: presumably it'd be the same thing as if you awaited `new Promise(() => {})` (a promise that never settles)
00:17:46  <ljharb>caiolima_: ie, the async function (and the resulting promise from it) would simply never settle either
00:17:49  * Bakkotquit (Client Quit)
00:18:47  <caitp>ljharb: I think that could potentially break apps
00:19:11  <caitp>like, if a Promise from some web service API was cancelled by non-user controlled JS, sites could break
00:20:15  * Bakkotjoined
00:21:12  <caiolima_>ljharb: hum...it sounds buggy to me. this case looks like a fancy a "while(true) {}" IMHO.
00:22:15  * Bakkotquit (Client Quit)
00:23:36  * Bakkotjoined
00:24:47  <caiolima_>I need to get more context about that, but one idea I had in mind is to use a new "CancellablePromise" and then let user use it to trigger promises that they want to cancel. in that case, we could throw when the an awaited promise is canceled.
00:25:46  <caiolima_>btw, "promising canceling" sounds cruel to me. It is rude break a promise =(
00:26:01  * Bakkotquit (Client Quit)
00:28:10  * Bakkotjoined
00:38:03  <ljharb>caitp: wait - can "not the creator of the promise" cancel them in this new proposal?
00:38:21  <ljharb>caiolima_: the creator of the promise can always give you a forever-pending promise and you have no control over it.
00:38:32  <ljharb>caiolima_: so the *creator* could always cancel, and the consumer would just never see a rejection or resolution, and that'd be ok
00:38:49  <ljharb>but if someone who didn't create the promise could cause its state to change, then that's not ok
00:38:57  <caitp>I don't see how that's okay if critical code is blocking on that promise being resolved
00:39:16  <caitp>you'd need to interrupt it to prevent it from blocking forever
00:39:25  <caitp>or at least make it possible to
00:43:26  <ljharb>caitp: it's ok because it's already possible
00:43:36  <ljharb>if i'm giving you the promise, you can't prevent me from giving you `new Promise(() => {})`
00:43:55  <ljharb>awaiting that is identical to sticking `.then` or `.catch` on said forever-pending promise
00:45:04  <caitp>yes, but people tend to not rely on things that can actually do that
00:45:11  <caitp>but people might actually rely on things that can be cancelled
00:45:19  <ljharb>and they will thus tend to not doing that anymore.
00:45:59  <ljharb>i agree that relying on a cancellable operation, without a means to hook into said cancellation, is dangerous - and if `fetch` starts being that, then relying on it without a cancellation hook will become dangerous
00:46:11  <ljharb>but that's not "not ok", that's just a hazard that fetch will be opting into
00:54:01  <caitp>I think it's an important cross-cutting thing, working with await needs to be a thing
00:54:53  * Bakkotquit (Quit: death)
00:56:07  <caiolima_>ljharb: what do you mean when you refer the creator of the promise?
00:56:13  * Bakkotjoined
00:56:29  <ljharb>caitp: working with await is a good thing; but awaiting a forever-pending promise already waits forever.
00:56:33  <ljharb>so that can't be a blocker here.
00:56:41  <ljharb>caiolima_: i mean, whoever did `new Promise` or `Promise.resolve` or `Promise.reject`
00:56:57  <caitp>cancelation is a form of resolution
00:57:10  <caitp>so no, I don't think s
00:57:34  <ljharb>it depends on if you view cancelation as a third state, or as a special form of rejection
00:57:54  <ljharb>in the former case, everything's fine - it's just invisible to people only using then/catch to subscribe. in the latter case, .catch would catch it
00:58:02  <caitp>its a non-pending state, period
00:58:03  <ljharb>(ofc, Promise#finally would absolutely react to rejections)
00:58:06  <ljharb>yes
00:58:21  <ljharb>but prior to "finally", promises do not give you a guarantee of notification when a promise stops being pending
00:58:30  <ljharb>so "a non-pending state" isn't something that you can be sure you'll ever get
00:58:35  <ljharb>* notified of
00:58:49  <ljharb>however, `finally` *would* have that guarantee - it would fire whenever the promise became non-pending, period
00:59:04  <caitp>with apis that people actually consume, you can be sure
01:00:57  <ljharb>i totally get that people's expectation will be that then+catch guarantees them "non-pending", but that expectation is already wrong
01:01:10  <ljharb>that's why i think "finally" is so important to add; because finally's semantics *are* "guaranteed non-pending"
01:04:59  <caitp>I don't think I agree with that line of thinking, this would make it very easy to break await-users
01:08:44  <caiolima_>we need to be sure to take the users expectation as intuitive as possible. Await is a really new thing, but the way I've used it was always considering a resolution, whatever it is. mainly because it's there to make async code more synchronous-like reading style.
01:29:59  <caitp>also re "but prior to "finally", promises do not give you a guarantee of notification when a promise stops being pending", I think it was always possible to get notified when the Promise was settled with await, regardless of "finally"
01:30:32  <caitp>fulfill -> try block, reject -> catch block
01:42:17  * not-an-aardvarkjoined
01:44:21  <rbuckton>caitp, sorry to chime in so late on the discussion, as I was pulled away. There are currently two possibilities for an await when an async operation is cancelled: 1. The operation never completes, and the `await` remains in a forever pending state. 2. Cancellation results in promise rejection, and an exception is thrown at the `await`.
01:44:52  <caitp>right, and I think option 1 is not workable
01:44:58  <caitp>option 2 isn't that great either, but it's workable
01:46:17  <rbuckton>There are two additional options to consider: 3. The async operation chooses to resolve in a clean state (useful for a cancellation token that is primarily used only to stop a long-running operation). 4. A new state is added to Promise to specifically track cancellation.
01:47:02  <rbuckton>In the .NET framework, you have [4] available when working directly with Tasks, but an `await` on a cancelled promise results in [2].
01:48:42  <rbuckton>Then again, the .NET framework uses cooperative cancellation between Tasks (Promises) and cancellation tokens, allowing for a tighter coupling between the two than something like what I support in the 'prex' library.
01:48:43  <caitp>yeah, I've thought about option 3, but it seems problematic because it doesn't really allow for handling of the cancellation, and doesn't allow overriding the resulting value
01:50:20  <caitp>and even stranger for async generators
01:50:21  <rbuckton>In .NET you handle cancellation in one of two ways: Direct interaction with the Task via ContinueWith (similar to 'Promise#then'), or by catching an exception. From a syntax perspective, there's no third rail for cancellation.
01:52:49  <rbuckton>As it stands with the 'prex' implementation, options 1-3 are all available to the developer as a choice. I can observe a cancellation signal with `token.register` and choose to either `resolve()`, `reject()`, or do nothing. I can make it easier to trigger rejections in an async function through `token.throwIfCancellationRequested()`, which throws a specific `CancelError` exception.
01:53:35  <rbuckton>That approach is similar to .NET Tasks and cancellation, which as worked well in .NET with async/await for a number of years now.
02:01:18  <caitp>the thing with async functions is, the Task interface isn't exposed to the caller
02:01:22  <caitp>they can't get at it
02:02:58  <caitp>I think the simplest thing to interact with would be to reject with a cancellation token, so that no third prong needs to be added
02:03:07  <caitp>not an ideal api, but fits better with async/await
02:16:48  <rbuckton>I'm not sure I understand what you mean by "reject with a cancellation token"
02:17:39  <rbuckton>Do you mean to say that if my asynchronous operation receives a cancellation signal, I should reject the operation's Promise with the token, rather than something derived from Error?
03:04:18  <bterlson>2 seems like the only option
03:05:12  <bterlson>I am not sure about deriving from Error
03:05:24  * bradleymeckjoined
03:05:37  <bterlson>it's not an error
03:09:58  * bradleymeckquit (Ping timeout: 256 seconds)
03:13:35  <Domenic>rbuckton: we're not really interested in something host-agnostic anymore. We tried that in TC39 and failed, so that effort is over.
03:14:03  <Domenic>Similarly we're not interested in good ergonomics (e.g. trying to treat a cancelation as a non-error) anymore. We tried that in TC39 and it failed.
03:15:22  <Domenic>bterlson: I think the editing downsides outweigh the benefits of every step being linkable in a way that survives across revisions, yeah.
03:27:20  <ljharb>Domenic: so the whatwg cancellation stuff, is there a tldr somewhere? (like, is it "third state"; how does one catch cancellations, with API if not with syntax; if a cancellation is a rejection, how does one identify that a rejection reason is a cancellation; etc)
03:27:51  <Domenic>The PR is as good as you're gonna get. Not my proposal so not going to spend time educating people on it; still trying to stay uninvolved, except that streams will have to use it.
03:43:00  <rbuckton>bterlson, it seems bad form to throw/catch something that is not an Error, as you cannot guarantee stack information.
04:17:40  * gskachkov_joined
04:18:25  * gskachkov_quit (Client Quit)
04:34:34  * jmdyckquit (Quit: Leaving.)
04:40:43  * gskachkov_joined
04:51:45  * gskachkov_quit (Quit: gskachkov_)
05:06:28  * bradleymeckjoined
05:12:25  * bradleymeckquit (Ping timeout: 268 seconds)
06:31:42  * gskachkov_joined
07:32:14  * gskachkov_quit (Quit: gskachkov_)
07:33:59  * gskachkov_joined
07:51:40  <annevk>Nothing like a thread about how to name stuff to get everyone to contribute
07:53:58  <ljharb>can't store your bike unless it's under the right color
07:58:07  <annevk>rbuckton: I'd love a more elaborate version of your last sentence here
07:58:18  <annevk>rbuckton: it sounds intriguing
07:58:58  <annevk>But yeah, the current TL;DR is that cancelation will reject the promise with some TBD exception
07:59:52  <ljharb>annevk: ok so it'd still trigger .catch and all the normal things?
08:00:02  <annevk>ljharb: yes
08:00:09  <ljharb>annevk: will there be a cross-realm way to determine if the rejection reason is a cancellation? meaning, not `instanceof`?
08:00:46  <annevk>ljharb: I was about to suggest we pick a unique DOMException name
08:01:17  <annevk>ljharb: we could do a more JavaScripty exception, but we already use an event handler so Domenic made the argument there's no real need to go there
08:01:31  <ljharb>annevk: my request would be something that is unforgeable.
08:01:42  <ljharb>annevk: iow, not `Object.prototype.toString.call`
08:01:49  <rbuckton>annevk, it generally feels like a bad practice to throw something that isn't an Error, as most people expect the result to be an Error or some subclass of Error. Yes, you can `throw "foo"`, but it won't capture the stack trace.
08:01:51  <ljharb>annevk: something that does a brand check
08:02:06  <annevk>rbuckton: DOMException is an Error
08:02:50  <annevk>ljharb: I see, proposal on the table would just be exc.name === ?
08:02:57  <ljharb>ugh
08:03:09  <ljharb>annevk: my hope would be something like `CancelException.is()`
08:03:10  <rbuckton>And that's fine. I was responding to the suggestion to reject the promise with the cancellation token itself on cancellation. For an `await`, that's akin to throwing the cancellation token as the error.
08:03:16  <ljharb>annevk: like `Array.isArray`, for the same reasons.
08:03:20  <annevk>ljharb: if there's a good reason I'm sure we can go there
08:03:41  <annevk>ljharb: I recommend leaving a comment with the rationale in https://github.com/whatwg/dom/pull/434 and I'll make sure we go through it
08:03:45  <ljharb>ok thanks
08:04:05  <annevk>rbuckton: ah okay, that's not the proposal
08:04:28  <annevk>rbuckton: it would be genuine error, with flavor TBD
08:05:34  <ljharb>annevk: posted https://github.com/whatwg/dom/pull/434#issuecomment-292470236 , thanks
08:06:00  <annevk>ljharb: you haven't really explained "why" though, which is what's needed to convince others :-)
08:06:17  <ljharb>i thought "all the same reasons as Array.isArray" would cover that
08:06:24  <ljharb>but i can try to flesh it out
08:06:42  <annevk>That'd be appreciated, since it's not immediately obvious to me those reasons apply here
09:09:09  * bradleymeckjoined
09:13:20  * bradleymeckquit (Ping timeout: 246 seconds)
10:26:00  * mylesborinsquit (Quit: farewell for now)
10:26:30  * mylesborinsjoined
10:59:58  * bradleymeckjoined
11:04:26  * bradleymeckquit (Ping timeout: 240 seconds)
11:08:53  * not-an-aardvarkquit (Quit: Connection closed for inactivity)
11:09:34  * gskachkov_quit (Quit: gskachkov_)
11:31:36  * bradleymeckjoined
11:33:33  * gskachkov_joined
11:35:47  * bradleymeckquit (Ping timeout: 246 seconds)
11:36:03  * jmdyckjoined
11:43:01  <annevk>So http://web.mit.edu/jwalden/www/isArray.html is a pretty good read, but all those problems also apply to platform objects and various other JavaScript objects. Why not have it for Map and Set?
11:58:42  * gskachkov_quit (Quit: gskachkov_)
12:08:32  * gskachkov_joined
12:39:56  * bradleymeckjoined
12:44:06  * bradleymeckquit (Ping timeout: 240 seconds)
12:49:03  * bradleymeckjoined
12:53:28  * bradleymeckquit (Ping timeout: 240 seconds)
13:15:40  * bradleymeckjoined
13:16:01  * bradleymeckquit (Client Quit)
13:50:08  * gskachkov_quit (Quit: gskachkov_)
14:22:24  * Fishrock123joined
15:49:37  * gskachkov_joined
15:59:10  * gskachkov_quit (Quit: gskachkov_)
15:59:40  * gskachkov_joined
16:14:12  * gskachkov_quit (Quit: gskachkov_)
16:16:04  * gskachkov_joined
16:38:29  * Fishrock123quit (Remote host closed the connection)
16:40:27  * gskachkov_quit (Quit: gskachkov_)
17:39:56  * Fishrock123joined
17:44:28  * Fishrock123quit (Ping timeout: 240 seconds)
18:10:39  * Fishrock123joined
18:16:07  * Fishrock123quit (Remote host closed the connection)
18:35:39  * gskachkov_joined
18:36:21  * gskachkov_quit (Client Quit)
18:39:35  * sebmckjoined
18:40:22  * gskachkov_joined
18:44:22  * sebmckquit (Client Quit)
18:45:59  * Fishrock123joined
19:07:28  * Fishrock123quit (Remote host closed the connection)
19:08:07  * Fishrock123joined
19:12:09  * Fishrock123quit (Ping timeout: 240 seconds)
19:16:10  * gskachkov_quit (Quit: gskachkov_)
19:23:23  * gskachkov_joined
19:27:36  * sebmckjoined
20:14:17  <ljharb>annevk: ok how about https://github.com/whatwg/dom/pull/434#issuecomment-292640413 for a bit more involved justification
20:14:40  <ljharb>annevk: and i tried to get brand-checking methods on everything, but was told that a prototype method that does a brand check and throws is sufficient
20:15:12  <ljharb>annevk: so i made an npm module to brand-check each kind of thing - i can do it for everything but Error, and Error.isError was rejected in favor of me agreeing to do the stacks proposal, which provides a brand-checking method.
20:27:15  <rbuckton>annevk: Given the discussion yesterday on cancellation, I put together a rather unformal strawman for ECMAScript cancellation primitives here: https://gist.github.com/rbuckton/9473f7303f2fa0b80f3fa7d1a7118ac3
20:31:35  <bterlson>After talking with a few people, I'm fairly confident we could standardize something like this in TC39. The takeaway from the previous failure was the typical lesson: new syntax is hard to advance. Cancellation token machinery should be drastically easier (and can have syntax sugar added over time if we want)
20:48:37  * Fishrock123joined
21:06:23  * gskachkov_quit (Quit: gskachkov_)
21:08:12  * sebmckquit (Quit: My MacBook has gone to sleep. ZZZzzz…)
21:57:07  * not-an-aardvarkjoined
22:08:12  * bradleymeckjoined
22:14:42  <bradleymeck>anyone know the exact special features of a template literal tail / why ESTree would make it a boolean https://github.com/estree/estree/blob/master/es2015.md#templateelement?
22:15:39  <ljharb>bradleymeck: could a tagged template literal appear in tail position?
22:17:05  <bradleymeck>well it just refers to the last segment of a template literal, not TCO tail position
22:19:28  <ljharb>ah ok
22:19:31  <ljharb>not sure then
22:29:37  * Fishrock123quit (Read error: Connection reset by peer)
22:30:05  * Fishrockjoined
22:35:13  * gskachkov_joined
22:46:23  * bradleymeckquit (Quit: bradleymeck)
22:46:24  * gskachkov_quit (Quit: gskachkov_)
23:22:03  * Fishrockquit (Quit: Leaving...)