tc39 / proposal-cancelable-promises

Former home of the now-withdrawn cancelable promises proposal for JavaScript
Other
376 stars 29 forks source link

`catchCancel` is a wrong word #11

Closed NekR closed 8 years ago

NekR commented 8 years ago

As you said in https://github.com/domenic/cancelable-promise/blob/master/Third%20State.md, cancelation isn't a error, even thought it may look similar.

In JS, catch is used simultaneously with exceptions. So, if an Exception is raised--it can be caught. Cancelation doesn't raise exception and shouldn't.

Plus, if you plan to add try..catch..cancel..finally it will be confusing, because it one place it's explicitly separated from catch, in other place (Promise#catchCancel) it has catch word in it.

domenic commented 8 years ago

The proposed syntax is

try {
  ...
} catch (e) {
  ...
} catch cancel (r) {
  ...
} finally {
  ...
}

with of course other permutations allowed, such as omitting any of the three non-try clauses, or switching around the order of catch and catch cancel.

There may be alternatives and we can leave this issue open to track such alternatives, but in general modifying existing grammars is very difficult, and catch is one of the only escape valves we have to allow this. For example, something like

try {
  ...
} catch (e) {
  ...
} cancel (r) {
  ...
}

does not work, as it's equivalent to

try {
  ...
} catch (e) {
  ...
}

cancel(r);

{
  ...
}

So if there is a way to avoid using catch when designing the syntactic construct for catching exceptions, it is not immediately obvious. I'd welcome suggestions from grammar experts (but would prefer to avoid speculation from those who aren't familiar with how to implement a parser). Probably the easiest thing to do would be to use an existing reserved keyword, but I can't think of any reasonable ones (try { ... } enum (r) { ... }, lol).

Anyway, I think it's fine to generalize the meaning of "catch" as a word to including catching cancelations, and not just exceptions. Sure, in an ideal world starting from scratch, maybe we'd use something different. But given what we have to work with, it's not so bad.

inikulin commented 8 years ago

I guess it will be catch.cancel for consisteny if throw.cancel will be a final syntax?

domenic commented 8 years ago

Maybe, although I am not a big fan of throw.cancel. I plan to spend some time next week when I'm back to working on this full time trying to work through the possibilities for both syntaxes.

nlwillia commented 8 years ago

Have you considered else as a reserved word option? Aborting an operation is essentially a conditional branch where the condition is deferred or asynchronous, and the universally understood and intuited complement to "if/then" is "else". catch has such a strong association with error handling that building off of it feels more like a concession to the realities of parsing than the cleanest possible expression of the idea. In a perfect world, maybe we'd choose a slightly different word, but promises already use "then", and "else" goes right along with that.

try {
} else (x) {
} catch (e) {
}
if (!confirm(...)) {
   else 'canceled';
}
fetch(...).then(...).else(...);

edit: Move else before catch.

ljharb commented 8 years ago

That's a clever idea, but else implies to me that it runs like finally but only when no exception was thrown.

shicks commented 8 years ago

Why use such drastically new syntax? It seems like a more generally-useful approach would be to simply define a new global class CancelError extends Error and then throw/catch that. Then if you really want new syntax, allow

try {
  // 1
} catch (CancelError as e) {
  // 2
} catch (e) {
  // 3
}

This has an obvious desugaring by simply bundling all the catches together and going down the list of types

try {
  // 1
} catch (e) {
  if (e instanceof CancelError) {
    // 2
  } else {
    // 3
  }
}

Also as is an already-existing contextual keyword with similar meaning in import, so that also seems like a win.

domenic commented 8 years ago

Please read the contents of this repository, such as the readme or third state.md, to understand why cancelation is not a type of error.

shicks commented 8 years ago

I have read the contents. I suppose what I'm disagreeing with is your premise that cancellation is not a type of error. As you point out - it's certainly a lot closer in spirit to a rejection than it is to a resolution. You claim that it is "not exceptional" because the user or the programmer initiated it. But from the standpoint of the code that's running and expecting a value from its await foo() call, exceptional is exactly what it is. I agree that it's awkward and burdensome to expect catch blocks to check what type of exception they got, but it's equally awkward to not allows them to see the cancellations in the first place. The fundamental problem comes down to the fact that when I read } catch (e) {, I have no way of knowing whether the developer meant "only deal with 'real' exceptions" or "no really, I want everything".

I would love to see cancelable promises land, but I worry that such drastic and breaking behavior change is infeasible and will prevent it from ever happening. A more conservative approach may be more tenable.

benjamingr commented 8 years ago

@shicks so basically you're saying that cancellations should not be caught by } catch (e) { but are not rejections? I think that's just a renaming of the current proposal.

Cancellations are not rejections, even if they're closer to a rejection than to a resolution. I currently write a lot of code with cancellation in C# (where it is an error) and honestly it sucks really bad because I have to catch exceptions that are not cancellations everywhere.

domenic commented 8 years ago

catch cancel is gone so closing this.