This is an archived snapshot of W3C's public bugzilla bug tracker, decommissioned in April 2019. Please see the home page for more details.

Bug 25048 - consider whether an IDL attribute of type Promise<T> should catch exceptions and wrap them up as a rejected Promise like they are for operations
Summary: consider whether an IDL attribute of type Promise<T> should catch exceptions ...
Status: RESOLVED FIXED
Alias: None
Product: WebAppsWG
Classification: Unclassified
Component: WebIDL (show other bugs)
Version: unspecified
Hardware: PC All
: P2 normal
Target Milestone: ---
Assignee: Cameron McCormack
QA Contact: public-webapps-bugzilla
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2014-03-14 02:14 UTC by Cameron McCormack
Modified: 2017-01-20 08:24 UTC (History)
6 users (show)

See Also:


Attachments

Description Cameron McCormack 2014-03-14 02:14:04 UTC

    
Comment 1 Boris Zbarsky 2014-03-14 02:20:37 UTC
Are there use cases for attributes of Promise type where this would make sense?  They wouldn't be creating a new Promise each time, so it's not like the Promise would represent a operation the attribute getter triggered....
Comment 2 Domenic Denicola 2014-03-14 02:24:38 UTC
In general, anytime someone is expecting to interface with an asynchronous API, they are expecting asynchronous errors, which are caught via `.catch(e => ...)`. It is very surprising if a synchronous error is thrown. If an API is known to cause both types of errors, you need both `.catch(e => ...)` and `catch(e) { ... }`, which is frustrating.

So yes, I think this change would make sense. I'm not sure under what situations it would get triggered---how exception-prone are the operations performed by getters, usually?---but philosophically, it's definitely desirable.
Comment 3 Cameron McCormack 2014-03-14 02:26:46 UTC
It's not so common for IDL attributes to throw exceptions on getting, but not unheard of.

Hmm, what if you had an IDL attribute of a Promise<T> type that throws when assigning?
Comment 4 Boris Zbarsky 2014-03-14 02:27:40 UTC
The question is whether there are ever use cases in which a promise attribute is is actually representing asynchronous API.

Or to put this another way: are there any use cases for allowing attributes of Promise type at all?

> how exception-prone are the operations performed by getters, usually?

It depends on the getter.  The most common practical source of exceptions is if you .call() the getter function on a wrong kind of object.
Comment 5 Domenic Denicola 2014-03-14 02:34:27 UTC
> Or to put this another way: are there any use cases for allowing attributes of Promise type at all?

For sure! See all the usage in [1] or [2]. Or, the recently-proposed loaded/ready promises could easily be attributes, if not for the fact that most of those resources allow you to reload them (e.g. by setting `.src` again).

> The most common practical source of exceptions is if you .call() the getter function on a wrong kind of object.

This should return a rejected promise for the same reason; if you are using a getter representing an asynchronous result, you should expect to be able to do asynchronous error handling.

> Hmm, what if you had an IDL attribute of a Promise<T> type that throws when assigning?

Yeah, this is trickier to reason about---mainly because I don't know of a reasonable use case for promise attributes with setters. I assume there'd be coercion behavior, so e.g. for a Promise<long> attribute these would be fine:

foo.bar = 5;
foo.bar = Promise.resolve(5);

but these would not:

foo.bar = {};
foo.bar = Promise.resolve(function () { });

I would probably again argue that the result should be `foo.bar` set to a promise rejected with a `TypeError`, since people would access the result of the set via

foo.bar.then(processValueRepresentedByBar, couldNotGetValue);

and would be surprised if they had to write

try {
  foo.bar.then(getValueThatWasSet, couldNotGetValue);
} catch (e) {
  couldNotGetValue(e);
}


[1]: https://github.com/whatwg/streams
[2]: https://rawgithub.com/ClaesNilsson/raw-sockets/gh-pages/index.html#interface-tcpsocket
Comment 6 Cameron McCormack 2014-03-14 02:37:18 UTC
(In reply to Domenic Denicola from comment #5)
> > Hmm, what if you had an IDL attribute of a Promise<T> type that throws when assigning?
> 
> Yeah, this is trickier to reason about---mainly because I don't know of a
> reasonable use case for promise attributes with setters. I assume there'd be
> coercion behavior, so e.g. for a Promise<long> attribute these would be fine:
> 
> foo.bar = 5;
> foo.bar = Promise.resolve(5);
> 
> but these would not:
> 
> foo.bar = {};
> foo.bar = Promise.resolve(function () { });
> 
> I would probably again argue that the result should be `foo.bar` set to a
> promise rejected with a `TypeError`, since people would access the result of
> the set via
> 
> foo.bar.then(processValueRepresentedByBar, couldNotGetValue);

That's my initial feeling too.
Comment 7 Boris Zbarsky 2014-03-14 03:26:54 UTC
OK, I guess if you only have one promise representing your state then it makes sense to make it an attribute. But then I'm not sure it makes sense to have that attribute create-and-return promises when called with the wrong this object.

Put another way, I strongly feel like for attribute getters we should preserve the invariant that getter.call(obj) == getter.call(obj) tests true.

So I would argue we should require that getters that return promises not throw normally and allow them to throw if invoked on an object that's the wrong type.  In practice, I don't expect anyone to be doing that sort of thing anyway.

As far as setters, if we have no use cases, let's not add complexity and just disallow them.  WebIDL already has too many unused (and never will be used!) things that just make it more complex than it should be.
Comment 8 Domenic Denicola 2016-10-13 13:37:19 UTC
(In reply to Boris Zbarsky from comment #7)
> OK, I guess if you only have one promise representing your state then it
> makes sense to make it an attribute. But then I'm not sure it makes sense to
> have that attribute create-and-return promises when called with the wrong
> this object.
> 
> Put another way, I strongly feel like for attribute getters we should
> preserve the invariant that getter.call(obj) == getter.call(obj) tests true.

I disagree that this invariant applies here. Its synchronous analogue is saying that getter.call(obj), when it fails, should always throw the same error. It's OK to return a different promise in the failure cases.

> As far as setters, if we have no use cases, let's not add complexity and
> just disallow them.  WebIDL already has too many unused (and never will be
> used!) things that just make it more complex than it should be.

Sounds good to me to disallow promise types with setters.
Comment 9 Boris Zbarsky 2016-10-13 14:03:52 UTC
> Its synchronous analogue is saying that getter.call(obj), when it fails,
> should always throw the same error.

This argument basically says to me that the basic idea of getters with Promise return values is wacky and we should be using a method instead...  But I accept that others disagree on this.
Comment 10 Anne 2016-10-13 15:06:36 UTC
If you cannot depend on === for promises due to the error case, do promises for IDL attributes need to ban [SameObject]?
Comment 11 Boris Zbarsky 2016-10-13 15:09:31 UTC
That really depends on the meaning people imbue [SameObject] with.  The ambiguity is pretty unfortunate, I agree.
Comment 12 Tobie Langel 2017-01-20 08:24:51 UTC
Fixed in https://github.com/heycam/webidl/commit/4c9c298