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

What to do about specs that need lots of error types #1219

Open
domenic opened this issue Oct 16, 2022 · 4 comments
Open

What to do about specs that need lots of error types #1219

domenic opened this issue Oct 16, 2022 · 4 comments

Comments

@domenic
Copy link
Member

domenic commented Oct 16, 2022

Spinning this off from #1211 since I think it deserves its own discussion:

@dandrader made me aware that the case he's working on is unlike RTCError or WebTransportError (or the pull request's WidgetError) in that he basically just needs more error types.

Specifically, his case is a smart card API, which has ~15 different SmartCard-specific error codes. (It seems like the plan is to expose a subset of these to the web.)

I see several routes we could go for this sort of API:

  1. Encourage a subclass of DOMException, e.g. SmartCodeError, with a separate responseCode property which is one of the ~15 values.
    1. Sub-variant: specs just define their own subclasses, with no coordination.
    2. Sub-variant: we add the subclasses to a registry in Web IDL, e.g. similar to the error names table.
  2. Add ~15 new smartcode-specific error names to Web IDL, e.g. "SmartCardNotReady", "SmartCardProtoMismatch", etc.
  3. Add ~10 new smartcode-specific error names to Web IDL, by having the SmartCard spec reuse some of the existing Web IDL error names. (Such as "NotFoundError" for SCARD_E_NO_SMARTCARD, or "NotAllowedError" for SCARD_E_SHARING_VIOLATION.)
  4. Let other specs, such as the SmartCard spec, use arbitrary error names, without Web IDL requiring them to be in the table.
    1. Sub-variant: it uses ~15 distinct new names. (Like (2).)
    2. Sub-variant: it uses ~10 distinct new names, reusing some existing names. (Like (3).)
  5. Have some minimal coordination/registration where other specs reserve "namespaces", e.g. "SmartCard*Error".

At first I was pushing for (1), but now I'm thinking one of the other options might be better. Especially since it's weird for an error to have three subtypes: DOMException > name = "SmartCardError" > responseCode = "not-ready" seems a bit excessive, compared to idiomatic JavaScript errors which just have one level (TypeError, SyntaxError, etc.).

Some prior art:

  • There are several error codes in Web IDL which are clearly IndexedDB-specific or DOM-specific.
  • https://wicg.github.io/serial/ just makes up several error names: "BufferOverrunError", "BreakError", "FramingError", "ParityError". (It also uses many other existing names, such as "InvalidStateError", "NetworkError", "SecurityError".) /cc @reillyeon

What do others think? I guess the main questions are: (a) should DOMException's name be reserved for generic broad categories, or is it OK to allow spec-specific error names; and (b) if we do allow spec-specific error names, should Web IDL's error names table act as a coordination point, or should we just let specs do what they want?

@annevk
Copy link
Member

annevk commented Oct 19, 2022

I tend to see it as only two levels, name and responseCode. At least without cross-global instanceof you wouldn't want to rely on that.

I guess it depends a bit on the exact use cases and how developers are expected to deal with it. Also, do they need to branch on things besides smartcode-specific exceptions, e.g., "SyntaxError" or "InvalidStateError"?

domenic added a commit that referenced this issue Oct 20, 2022
Also be clearer about how exception names are meant to be used, at least for now (pending discussion in #1219).

See discussion in #1168 (comment). Closes #1223.

This also includes some updates to all exception creation and throwing, such as reflecting how messages are actually passed along in practice, or using Web IDL infrastructure to create DOMException instances instead of Construct()ing them.
domenic added a commit that referenced this issue Oct 20, 2022
Also be clearer about how exception names are meant to be used, at least for now (pending discussion in #1219).

See discussion in #1168 (comment). Closes #1223.

This also includes some updates to all exception creation and throwing, such as reflecting how messages are actually passed along in practice, or using Web IDL infrastructure to create DOMException instances instead of Construct()ing them.
@domenic
Copy link
Member Author

domenic commented Oct 20, 2022

I tend to see it as only two levels, name and responseCode. At least without cross-global instanceof you wouldn't want to rely on that.

The first level is reliable cross-realm using .constructor.name. (For JS spec exceptions, .constructor.name === .name, but DOMExceptions departed from that... ah, memories.)

I guess it depends a bit on the exact use cases and how developers are expected to deal with it. Also, do they need to branch on things besides smartcode-specific exceptions, e.g., "SyntaxError" or "InvalidStateError"?

@dandrader knows the specific case better, but I could easily imagine some sort of "get me a smartcard" API which can fail with:

  • TypeError because you typoed it as getMeASmartCrd(). (Developers want to "branch" on this by not catching it and letting it hit window.onerror.)
  • "NotAllowedError" DOMException because the user denied permission. (Developers want to branch on this and say "no, please click 'ok' to the permission prompt next time!")
  • A variety of SmartCard-specific errors, e.g. corresponding to SCARD_E_NO_SMARTCARD or SCARD_E_NOT_READY, which they branch on to translate into friendlier user-specific errors.

Similar patterns can be seen with the Web Serial case, where I am pretty sure @reillyeon added the separate errors because developers are expected to take different actions depending on them. And #1168 indicates a desire to distinguish two different types of aborts, one where the user presses "Cancel" and one where the user opts out of the process (which is, somehow, different?).

@annevk
Copy link
Member

annevk commented Oct 27, 2022

Right, but in that case isn't a single exception type for all SmartCard stuff kinda nice? At least it seems likely you might have shared logic there whereas you wouldn't necessarily with the other two exceptions.

@dandrader
Copy link

But when you don't have shared error handling logic among all errors of a given specialised error class then this two-layered approach is a hindrance instead of an asset.

The benefit I see in having a specialised error class is not polluting the DOMException.name namespace, at the cost of a more complex error type (with inheritance and two members, "name" and "responseCode"), which inevitably leads into a two-layered error handling logic (again, more complexity). That assuming this "namespace pollution" is a problem in the first place.

If all smartcard-specific errors were also represented via specific DOMException.name values, one could for instance have a single map from DOMException.name value to error handling function. And that also wouldn't impede one from sharing code between error cases when appropriate. This looks better to me.

domenic added a commit that referenced this issue Jun 1, 2023
Also be clearer about how exception names are meant to be used, at least for now (pending discussion in #1219).

See discussion in #1168 (comment). Closes #1223.

This also includes some updates to all exception creation and throwing, such as reflecting how messages are actually passed along in practice, or using Web IDL infrastructure to create DOMException instances instead of Construct()ing them.
domenic added a commit that referenced this issue Jun 1, 2023
Also be clearer about how exception names are meant to be used, at least for now (pending discussion in #1219).

See discussion in #1168 (comment). Closes #1223.

This also includes some updates to all exception creation and throwing, such as reflecting how messages are actually passed along in practice, or using Web IDL infrastructure to create DOMException instances instead of Construct()ing them.
domenic added a commit that referenced this issue Jun 1, 2023
Also be clearer about how exception names are meant to be used, at least for now (pending discussion in #1219).

See discussion in #1168 (comment). Closes #1223.

This also includes some updates to all exception creation and throwing, such as reflecting how messages are actually passed along in practice, or using Web IDL infrastructure to create DOMException instances instead of Construct()ing them.
domenic added a commit that referenced this issue Jun 5, 2023
Also be clearer about how exception names are meant to be used, at least for now (pending discussion in #1219).

See discussion in #1168 (comment). Closes #1223.

This also includes some updates to all exception creation and throwing, such as reflecting how messages are actually passed along in practice, or using Web IDL infrastructure to create DOMException instances instead of Construct()ing them.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

3 participants