Re: [whatwg] Notifications: making requestPermission() return a promise

2014-10-08 Thread Anne van Kesteren
On Tue, Oct 7, 2014 at 8:33 PM, Tab Atkins Jr. jackalm...@gmail.com wrote:
 On Sun, Oct 5, 2014 at 7:41 AM, Anne van Kesteren ann...@annevk.nl wrote:
 On Thu, Oct 2, 2014 at 10:13 PM, Domenic Denicola
 dome...@domenicdenicola.com wrote:
 So we should make a choice, as to whether we want developers to assume they 
 will always get permission (in which case it should reject upon permission 
 not being granted), or whether we want developers to ask the API whether 
 they were granted permission (in which case it should give back a boolean 
 fulfillment value or similar).

 How can they assume permission is always granted? It's up the user.
 It's a request from the developer and the user can say no. What's
 unclear about the name?

 Yeah, you misunderstood the question.  It's about whether permission
 failure should reject the promise or accept it with a boolean.

Domenic did not ask a question. I asked a question since it's unclear
to me why a developer could reasonably assume they will always get
permission.


-- 
https://annevankesteren.nl/


Re: [whatwg] Notifications: making requestPermission() return a promise

2014-10-08 Thread Tab Atkins Jr.
On Oct 7, 2014 11:32 PM, Anne van Kesteren ann...@annevk.nl wrote:

 On Tue, Oct 7, 2014 at 8:33 PM, Tab Atkins Jr. jackalm...@gmail.com
wrote:
  On Sun, Oct 5, 2014 at 7:41 AM, Anne van Kesteren ann...@annevk.nl
wrote:
  On Thu, Oct 2, 2014 at 10:13 PM, Domenic Denicola
  dome...@domenicdenicola.com wrote:
  So we should make a choice, as to whether we want developers to
assume they will always get permission (in which case it should reject upon
permission not being granted), or whether we want developers to ask the API
whether they were granted permission (in which case it should give back a
boolean fulfillment value or similar).
 
  How can they assume permission is always granted? It's up the user.
  It's a request from the developer and the user can say no. What's
  unclear about the name?
 
  Yeah, you misunderstood the question.  It's about whether permission
  failure should reject the promise or accept it with a boolean.

 Domenic did not ask a question. I asked a question since it's unclear
 to me why a developer could reasonably assume they will always get
 permission.

You're missing context or something.

The question is whether it's not natural to assume that *if the promise
fulfills*, that means they got permission. This allows them to do things
like using Promise.all() to join multiple permission requests together and
get a nice combined promise that fulfills when everything succeeds, or
write a nice straight success path that assumes permission, and then handle
any errors, including denied permission, at the end, rather than
interleaving error-handling logic into the middle of your code.

~TJ


Re: [whatwg] Notifications: making requestPermission() return a promise

2014-10-08 Thread Anne van Kesteren
On Wed, Oct 8, 2014 at 9:51 AM, Tab Atkins Jr. jackalm...@gmail.com wrote:
 The question is whether it's not natural to assume that *if the promise
 fulfills*, that means they got permission. This allows them to do things
 like using Promise.all() to join multiple permission requests together and
 get a nice combined promise that fulfills when everything succeeds, or write
 a nice straight success path that assumes permission, and then handle any
 errors, including denied permission, at the end, rather than interleaving
 error-handling logic into the middle of your code.

Okay, given that question I agree it's natural to assume that this
happens when it resolves. However, a user declining permission is not
exceptional behavior and therefore should not cause an exception. In
synchronous code you would not want to write try/catch here.


-- 
https://annevankesteren.nl/


Re: [whatwg] Notifications: making requestPermission() return a promise

2014-10-08 Thread Tobie Langel
On Wed, Oct 8, 2014 at 9:51 AM, Tab Atkins Jr. jackalm...@gmail.com wrote:

 The question is whether it's not natural to assume that *if the promise
 fulfills*, that means they got permission. This allows them to do things
 like using Promise.all() to join multiple permission requests together and
 get a nice combined promise that fulfills when everything succeeds,


This is as simple as:

Promise.all(permissionRequests).then(function(results) {
if (results.every(x = x === granted)) // …
});

But I don't think it's the right approach to handling permissions in
general. Developers should handle granted permissions as progressive
enhancements, not balk when they don't get all the permissions they
required. Using exceptions for denied permissions sends a completely wrong
message imho, especially when it's combined with Promise.all.

--tobie


Re: [whatwg] Notifications: making requestPermission() return a promise

2014-10-08 Thread Tab Atkins Jr.
On Wed, Oct 8, 2014 at 1:07 AM, Anne van Kesteren ann...@annevk.nl wrote:
 On Wed, Oct 8, 2014 at 9:51 AM, Tab Atkins Jr. jackalm...@gmail.com wrote:
 The question is whether it's not natural to assume that *if the promise
 fulfills*, that means they got permission. This allows them to do things
 like using Promise.all() to join multiple permission requests together and
 get a nice combined promise that fulfills when everything succeeds, or write
 a nice straight success path that assumes permission, and then handle any
 errors, including denied permission, at the end, rather than interleaving
 error-handling logic into the middle of your code.

 Okay, given that question I agree it's natural to assume that this
 happens when it resolves. However, a user declining permission is not
 exceptional behavior and therefore should not cause an exception. In
 synchronous code you would not want to write try/catch here.

An error or failure event *is* an asynchronous exception.  It's a
completely different code path from the success event that you can
handle separately, while writing code for the success path that
assumes you got the things you needed.

Do you think that every single instance of error events we've used in
the past was a mistake, and we should have instead just had a
complete event that both success and failure used?  For example,
should img.onload fire when the image fails to load?  This is
*exactly* analogous to a permission request succeeding or failing, as
far as I can tell, but for the equivalent image situation, I believe
you're okay with a failed load rejecting the .ready promise (or
whatever we're planning to name it).

There are certainly cases where only actual exceptions would cause
rejection - Domenic's example of a userAllowsNotifications()
function is clearly going to fulfill with a boolean, and only reject
if you fuck something up.  But requesting a permission is an operation
that can fail, and failure is exceptional, and we've reflected this
precise distinction in tons of past APIs via an error event.  Why was
every single past API that used this pattern mistaken?

Again, if this means that the current design for await becomes less
convenient, *we can fix await to work better*. It's not set in stone,
it's not developed yet.  This is a thing we can change.  But let's not
twist our necks around and force promise APIs into an unnatural and
inconvenient shape just because a naive translation to sync code
produces errors and people find try/catch annoying or distasteful.

~TJ


Re: [whatwg] Notifications: making requestPermission() return a promise

2014-10-08 Thread Tab Atkins Jr.
On Wed, Oct 8, 2014 at 1:31 AM, Tobie Langel tobie.lan...@gmail.com wrote:
 On Wed, Oct 8, 2014 at 9:51 AM, Tab Atkins Jr. jackalm...@gmail.com wrote:

 The question is whether it's not natural to assume that *if the promise
 fulfills*, that means they got permission. This allows them to do things
 like using Promise.all() to join multiple permission requests together and
 get a nice combined promise that fulfills when everything succeeds,


 This is as simple as:

 Promise.all(permissionRequests).then(function(results) {
 if (results.every(x = x === granted)) // …
 });

 But I don't think it's the right approach to handling permissions in
 general. Developers should handle granted permissions as progressive
 enhancements, not balk when they don't get all the permissions they
 required. Using exceptions for denied permissions sends a completely wrong
 message imho, especially when it's combined with Promise.all.

I don't think moral arguments really have a place here.  Whatever
mitigation code that authors write to handle failed permissions can go
in the reject handler exactly as easily as in the fulfill handler.
That we believe authors should handle permission failures
intelligently doesn't, itself, mean that we should make the success
path less convenient.

~TJ


Re: [whatwg] Notifications: making requestPermission() return a promise

2014-10-08 Thread Tobie Langel
On Wed, Oct 8, 2014 at 5:59 PM, Tab Atkins Jr. jackalm...@gmail.com wrote:

 On Wed, Oct 8, 2014 at 1:31 AM, Tobie Langel tobie.lan...@gmail.com
 wrote:
  On Wed, Oct 8, 2014 at 9:51 AM, Tab Atkins Jr. jackalm...@gmail.com
 wrote:
 
  The question is whether it's not natural to assume that *if the promise
  fulfills*, that means they got permission. This allows them to do things
  like using Promise.all() to join multiple permission requests together
 and
  get a nice combined promise that fulfills when everything succeeds,
 
 
  This is as simple as:
 
  Promise.all(permissionRequests).then(function(results) {
  if (results.every(x = x === granted)) // …
  });
 
  But I don't think it's the right approach to handling permissions in
  general. Developers should handle granted permissions as progressive
  enhancements, not balk when they don't get all the permissions they
  required. Using exceptions for denied permissions sends a completely
 wrong
  message imho, especially when it's combined with Promise.all.

 I don't think moral arguments really have a place here.  Whatever
 mitigation code that authors write to handle failed permissions can go
 in the reject handler exactly as easily as in the fulfill handler.
 That we believe authors should handle permission failures
 intelligently doesn't, itself, mean that we should make the success
 path less convenient.


I don't see how your definition of success is less of a moral argument than
mine, but I'm happy to be enlightened.

--tobie


Re: [whatwg] Notifications: making requestPermission() return a promise

2014-10-08 Thread Domenic Denicola
From: Tab Atkins Jr. [mailto:jackalm...@gmail.com] 

 Again, if this means that the current design for await becomes less 
 convenient, *we can fix await to work better*. It's not set in stone, it's 
 not developed yet.  This is a thing we can change.

To be clear, this will not be happening. Await is designed very much to play 
well with promise semantics and to carry over the return value/thrown exception 
parallel even more directly than promises already do. As I said earlier, if 
you'd prefer some kind of Option type, perhaps with its own dedicated syntax, 
that's something you can try proposing. But await and promises are tied to 
exception semantics, have been since day 1, and are in all other languages 
which have similar constructs. Nobody on TC39 is planning to depart from that 
path, especially since async functions with these semantics have been proposed, 
in one form or another, since the early days of ES Harmony.

 But let's not twist our necks around and force promise APIs into an unnatural 
 and inconvenient shape just because a naive translation to sync code produces 
 errors and people find try/catch annoying or distasteful.

I disagree with your characterization of unnatural and inconvenient, of 
course. An `if` statement is the most natural thing in the world.

What I find interesting here is the claim that people find try/catch annoying 
or distasteful. Why should they? It's the proper, syntactic way to handle 
errors---none of this error event business, or error-first callbacks, or even 
promise rejection callbacks. That's how exceptional, stack-unwinding errors 
that are meant to immediately halt execution should be contained and handled.

The question, again, is very simple. Is being denied permission an exceptional 
error that developers want to bubble to the outermost `catch (e) { ... }` 
block, or outermost `.catch(e = { ... })` handler? Or will they always want to 
deal with both paths of the result immediately? Tobie's argument about treating 
permissions as progressive enhancement is a good argument for the latter, IMO.


Re: [whatwg] Notifications: making requestPermission() return a promise

2014-10-08 Thread Anne van Kesteren
On Wed, Oct 8, 2014 at 6:07 PM, Domenic Denicola
dome...@domenicdenicola.com wrote:
 What I find interesting here is the claim that people find try/catch annoying 
 or distasteful.

I don't think you should need try/catch for a common failure case.
That is all. So yes, agreed with Tobie et al.


-- 
https://annevankesteren.nl/


Re: [whatwg] Notifications: making requestPermission() return a promise

2014-10-08 Thread Domenic Denicola
From: annevankeste...@gmail.com [mailto:annevankeste...@gmail.com] On Behalf Of 
Anne van Kesteren

 I don't think you should need try/catch for a common failure case.

Ah, this is the crux of our minor-disagreement, I think.

IMO using try/catch for a common failure case is fine, *as long as you want 
that failure to bubble up the call stack*. E.g., if you want to handle it at a 
higher level along with other failures, or if you want to ignore the 
possibility of failure except in how errors get sent to `window.onerror`.

Now, I think we're likely in *agreement* that you don't actually want to do 
this for requestPermission---you should handle it as soon as possible. But our 
reasoning is different, and now I understand why.




Re: [whatwg] Notifications: making requestPermission() return a promise

2014-10-08 Thread Tab Atkins Jr.
On Wed, Oct 8, 2014 at 9:16 AM, Anne van Kesteren ann...@annevk.nl wrote:
 On Wed, Oct 8, 2014 at 6:07 PM, Domenic Denicola
 dome...@domenicdenicola.com wrote:
 What I find interesting here is the claim that people find try/catch 
 annoying or distasteful.

 I don't think you should need try/catch for a common failure case.
 That is all. So yes, agreed with Tobie et al.

You keep arguing from the future rejections become errors position.
You keep ignoring the past turns out we like using async errors for
'soft failures' of this kind, and have done it lots of times, and
nobody seems to complain argument.

Do you dislike img.onerror firing when the image doesn't load?  (And
same for all the other resource-loading elements.)  Do you dislike
geolocator.getCurrentPosition calling the failure callback when the
user refuses permission?  Do you dislike IDB firing error events on
several types of failure, ranging from exceptional to mundane?

If there are any of these you do *not* dislike, why?  And why doesn't
the logic from those apply to this situation?

On Wed, Oct 8, 2014 at 9:18 AM, Domenic Denicola
dome...@domenicdenicola.com wrote:
 Ah, this is the crux of our minor-disagreement, I think.

 IMO using try/catch for a common failure case is fine, *as long as you want 
 that failure to bubble up the call stack*. E.g., if you want to handle it at 
 a higher level along with other failures, or if you want to ignore the 
 possibility of failure except in how errors get sent to `window.onerror`.

 Now, I think we're likely in *agreement* that you don't actually want to do 
 this for requestPermission---you should handle it as soon as possible. But 
 our reasoning is different, and now I understand why.

The problem here is that try/catch *is* distasteful, while promise
rejection isn't, and it's all ergonomics.

* try/catch produces rightward drift, promise reject handlers do not
* errors bubble up indefinitely until they're caught, breaking all of
your code.  Rejections bubble down a single promise chain, and can be
ignored if you're done with a chain without anything bad happening.
(And some Promise algebra functions like .race() can swallow a
rejection without rejecting the chain, if another one fulfilled first,
so you don't even have to think about the rejection.)
* We've been taught not to use exceptions for control flow, but we
have the Promise algebra to help us do control flow based on promises
fulfilling/rejecting (and more mature Promise libraries tend to grow
more algebra over time).

Errors suck, but they're the way we do rejections syncly.  I hate that
we're compromising on the built-in ergonomics of Promises in order to
avoid triggering the worse ergonomics of errors in the future. :(

~TJ


Re: [whatwg] Notifications: making requestPermission() return a promise

2014-10-08 Thread Anne van Kesteren
On Wed, Oct 8, 2014 at 7:03 PM, Tab Atkins Jr. jackalm...@gmail.com wrote:
 You keep ignoring the past turns out we like using async errors for
 'soft failures' of this kind, and have done it lots of times, and
 nobody seems to complain argument.

A user saying no to notifications is not an error. You ask the user to
make a decision, the user decides. Either way is a success. An error
would be invoking the method in the wrong way.


 Do you dislike img.onerror firing when the image doesn't load?  (And
 same for all the other resource-loading elements.)

That makes sense. Network errors are rather exceptional. Note that it
does not error for a 404 (unless it can't decode the response, which
again, is rather exceptional).


 Do you dislike
 geolocator.getCurrentPosition calling the failure callback when the
 user refuses permission?

I would expect that to be done differently today, yes.


-- 
https://annevankesteren.nl/


Re: [whatwg] Notifications: making requestPermission() return a promise

2014-10-08 Thread Tab Atkins Jr.
On Wed, Oct 8, 2014 at 10:39 AM, Anne van Kesteren ann...@annevk.nl wrote:
 On Wed, Oct 8, 2014 at 7:03 PM, Tab Atkins Jr. jackalm...@gmail.com wrote:
 You keep ignoring the past turns out we like using async errors for
 'soft failures' of this kind, and have done it lots of times, and
 nobody seems to complain argument.

 A user saying no to notifications is not an error. You ask the user to
 make a decision, the user decides. Either way is a success. An error
 would be invoking the method in the wrong way.

This is 100% arguable, and based solely on the *precise* manner in
which you are assigning semantics to the name.

If we named the method getNotifier(), and it requested permission as
a side-effect, would you call failure to get the notifier due to
refusing permission an exceptional situation?

 Do you dislike img.onerror firing when the image doesn't load?  (And
 same for all the other resource-loading elements.)

 That makes sense. Network errors are rather exceptional. Note that it
 does not error for a 404 (unless it can't decode the response, which
 again, is rather exceptional).


 Do you dislike
 geolocator.getCurrentPosition calling the failure callback when the
 user refuses permission?

 I would expect that to be done differently today, yes.

Why?  getCurrentPosition is asking for the current permission.  If you
fail to get the current position, why would you call that a success?
What would you even pass to the success callback?  A neutered position
object?  A position object with default values, plus an extra field
saying lol no this isn't real?

~TJ


Re: [whatwg] Notifications: making requestPermission() return a promise

2014-10-08 Thread Olli Pettay

On 10/08/2014 08:03 PM, Tab Atkins Jr. wrote:

On Wed, Oct 8, 2014 at 9:16 AM, Anne van Kesteren ann...@annevk.nl wrote:

On Wed, Oct 8, 2014 at 6:07 PM, Domenic Denicola
dome...@domenicdenicola.com wrote:

What I find interesting here is the claim that people find try/catch annoying 
or distasteful.


I don't think you should need try/catch for a common failure case.
That is all. So yes, agreed with Tobie et al.


You keep arguing from the future rejections become errors position.
You keep ignoring the past turns out we like using async errors for
'soft failures' of this kind, and have done it lots of times, and
nobody seems to complain argument.

Do you dislike img.onerror firing when the image doesn't load?  (And
same for all the other resource-loading elements.)  Do you dislike
geolocator.getCurrentPosition calling the failure callback when the
user refuses permission?  Do you dislike IDB firing error events on
several types of failure, ranging from exceptional to mundane?

If there are any of these you do *not* dislike, why?  And why doesn't
the logic from those apply to this situation?

On Wed, Oct 8, 2014 at 9:18 AM, Domenic Denicola
dome...@domenicdenicola.com wrote:

Ah, this is the crux of our minor-disagreement, I think.

IMO using try/catch for a common failure case is fine, *as long as you want 
that failure to bubble up the call stack*. E.g., if you want to handle it at a 
higher level along with other failures, or if you want to ignore the 
possibility of failure except in how errors get sent to `window.onerror`.

Now, I think we're likely in *agreement* that you don't actually want to do 
this for requestPermission---you should handle it as soon as possible. But our 
reasoning is different, and now I understand why.


The problem here is that try/catch *is* distasteful, while promise
rejection isn't, and it's all ergonomics.

* try/catch produces rightward drift, promise reject handlers do not
* errors bubble up indefinitely until they're caught, breaking all of
your code.

(off topic to Notifications)
That is a main point of exceptions. If your code is horribly broken,
like wrong params passed to some method, execution should stop asap.
The fact that Promise returning functions don't throw immediately is a crazy 
setup
since one may just ignore and not notice at all the rather bad error in the
program logic.



Rejections bubble down a single promise chain, and can be
ignored if you're done with a chain without anything bad happening.
(And some Promise algebra functions like .race() can swallow a
rejection without rejecting the chain, if another one fulfilled first,
so you don't even have to think about the rejection.)
* We've been taught not to use exceptions for control flow, but we
have the Promise algebra to help us do control flow based on promises
fulfilling/rejecting (and more mature Promise libraries tend to grow
more algebra over time).

Errors suck, but they're the way we do rejections syncly.  I hate that
we're compromising on the built-in ergonomics of Promises in order to
avoid triggering the worse ergonomics of errors in the future. :(

~TJ





Re: [whatwg] Notifications: making requestPermission() return a promise

2014-10-08 Thread Jonas Sicking
On Wed, Oct 8, 2014 at 9:16 AM, Anne van Kesteren ann...@annevk.nl wrote:
 On Wed, Oct 8, 2014 at 6:07 PM, Domenic Denicola
 dome...@domenicdenicola.com wrote:
 What I find interesting here is the claim that people find try/catch 
 annoying or distasteful.

 I don't think you should need try/catch for a common failure case.
 That is all. So yes, agreed with Tobie et al.

Another thing to keep in mind here is that it's pretty easy to convert
between either of these behaviors. It's just a matter of either doing

requestPermission().then((r) = { if (!r) throw Error(...) })

requestPermission().then(() = true, () = false)

Or, using the await syntax

async function() {
  if (!await requestPermission())
throw Error(...);
}

async function() {
  hasPermission = true;
  try {
await requestPermission();
  }
  catch {
hasPermission = false;
  }
}

So I think a more important question here is what behavior would an
author expect. I think one of the points Dominic tried to make earlier
is that the name is important for setting that expectation and help
authors understand how the function behaves. Sadly the name that we're
stuck with doesn't really provide much guidance either way.

But I think to some extent it's indicating that we're bikeshedding here.

/ Jonas


Re: [whatwg] Notifications: making requestPermission() return a promise

2014-10-08 Thread Jonas Sicking
On Wed, Oct 8, 2014 at 10:39 AM, Anne van Kesteren ann...@annevk.nl wrote:
 On Wed, Oct 8, 2014 at 7:03 PM, Tab Atkins Jr. jackalm...@gmail.com wrote:
 You keep ignoring the past turns out we like using async errors for
 'soft failures' of this kind, and have done it lots of times, and
 nobody seems to complain argument.

 A user saying no to notifications is not an error. You ask the user to
 make a decision, the user decides. Either way is a success. An error
 would be invoking the method in the wrong way.

This is more of a coding pattern thing than an expectation thing.

For example in gecko we often implement security checks by calling
functions that throw exceptions if the security check failed. Mainly
because this means less typing. So rather than writing:

function implDOMThingy(x, y, z) {
  if (!callerCanAccess(x))
throw Error(...);

  if (!isSameOrigin(x,y))
throw Error(...);

  ... do stuff here ...
}

we write

function implDOMThingy(x, y, z) {
  assertCanAccess(x);
  assertSameOrigin(x,y);

  ... do stuff here ...
}

So assertCanAccess/assertSameOrigin throws exceptions if a given
security check doesn't pass. Not because the security function was
called the wrong way or otherwise had an error, but because it makes
callsites easier to write.

However the experience that I personally have with this pattern is
that it requires that the throwing function takes care of everything
that needs to happen when an exception is thrown. For us that meant
things like log errors to the developer console. So this is more
appropriate in places when the throwing function provides a complete
package of functionality.

This also means that the functions are less reusable. Since they don't
just do one thing.

But it is quite awesome when you have such a resuable package that you
can use in several callsites. Definitely makes the code less
cluttered.

But I think that's an indication that we should not do that here. I
would for example expect that authors want to put up some UI to the
user indicating that the reason some feature isn't working is because
the user has denied access.

/ Jonas


Re: [whatwg] Notifications: making requestPermission() return a promise

2014-10-07 Thread Tab Atkins Jr.
On Sun, Oct 5, 2014 at 7:41 AM, Anne van Kesteren ann...@annevk.nl wrote:
 On Thu, Oct 2, 2014 at 10:13 PM, Domenic Denicola
 dome...@domenicdenicola.com wrote:
 So we should make a choice, as to whether we want developers to assume they 
 will always get permission (in which case it should reject upon permission 
 not being granted), or whether we want developers to ask the API whether 
 they were granted permission (in which case it should give back a boolean 
 fulfillment value or similar).

 How can they assume permission is always granted? It's up the user.
 It's a request from the developer and the user can say no. What's
 unclear about the name?

Yeah, you misunderstood the question.  It's about whether permission
failure should reject the promise or accept it with a boolean.

~TJ


Re: [whatwg] Notifications: making requestPermission() return a promise

2014-10-05 Thread Anne van Kesteren
On Thu, Oct 2, 2014 at 10:13 PM, Domenic Denicola
dome...@domenicdenicola.com wrote:
 So we should make a choice, as to whether we want developers to assume they 
 will always get permission (in which case it should reject upon permission 
 not being granted), or whether we want developers to ask the API whether they 
 were granted permission (in which case it should give back a boolean 
 fulfillment value or similar).

How can they assume permission is always granted? It's up the user.
It's a request from the developer and the user can say no. What's
unclear about the name?


-- 
https://annevankesteren.nl/


Re: [whatwg] Notifications: making requestPermission() return a promise

2014-10-05 Thread Brian Kardell
On Oct 5, 2014 7:41 AM, Anne van Kesteren ann...@annevk.nl wrote:

 On Thu, Oct 2, 2014 at 10:13 PM, Domenic Denicola
 dome...@domenicdenicola.com wrote:
  So we should make a choice, as to whether we want developers to assume
they will always get permission (in which case it should reject upon
permission not being granted), or whether we want developers to ask the API
whether they were granted permission (in which case it should give back a
boolean fulfillment value or similar).

 How can they assume permission is always granted? It's up the user.
 It's a request from the developer and the user can say no. What's
 unclear about the name?


I think Domenic is saying do we want to give the impression that you code
the happy path only in the then(), or do we assume you are asking an async
question for which an async answer is given with information for you to
disambiguate in the then() regardless of whether this is happy or not.

I originally expected denial to throw, I admit, but this is mainly because
it was guessing on an unestablished pattern. If we establish something
which can be applied widely, most of that is mitigated. I think the later
(async question that always answers in .then()) makes much more sense
especially given that https://notifications.spec.whatwg.org has 3 such
values (accepted, denied, default) - if there is algebra to be done we can
experiment with some good patterns inside .then() to make that easier.

 --
 https://annevankesteren.nl/


Re: [whatwg] Notifications: making requestPermission() return a promise

2014-10-02 Thread Domenic Denicola
My previous replies to this thread have been about more general issues 
regarding promises and exceptions where I felt the need to jump in. Now, about 
the actual specific case at hand...

From: whatwg [mailto:whatwg-boun...@lists.whatwg.org] On Behalf Of Anne van 
Kesteren

 Otherwise I would never expect this promise to be rejected as the user 
 declining notifications is not exceptional.

I think this is a judgment call. The definition of exceptional is always a 
bit tricky. Really it comes down to, should the developer always handle this 
case or not?

For example, failures like a file being unreadable can be considered 
exceptional, since often a developer doesn't want to handle such failures, but 
instead wants to put a big try {} block around a bunch of logic, and if any of 
it failed, say something went wrong.

I also maintain that this is partially in how the function is named. For 
example, if your function is called `writeToFile()` or 
`acquireNotificationPermission()`, it can be considered exceptional for it to 
fail.

To illustrate this, let's work in a world with only-sync calls, since that 
reduces peoples confusion about this new promises concept and what's 
appropriate there. The developer will likely include such calls in a sequence 
of operations, one after the other, and expect none of them to fail:

```js
acquireNotificationPermission();
var data = prepareNotificationData();
showNotification(data);
removeFromNotificationQueue(data);
```

in this example, any failures in any of these steps will bubble up to 
window.onerror, and get sent to telemetry. That seems OK, and in-line with the 
intent of the code.

Whereas, if the function is named `userAllowsNotifications()`, it is much 
clearer that you would do

```js
var canNotify = userAllowsNotifications();
if (canNotify) {
  var data = prepareNotificationData();
  showNotification(data);
  removeFromNotificationQueue(data);
}
```

So to me, the question comes down to: do we want to design our APIs around the 
model of `acquireNotificationPermission()`, where the developer codes as if 
getting permission is an expected normal thing? Or do we want to code them 
around the model of `userAllowsNotifications()`, where the developer is 
explicitly asking a question?

To answer some contentions that the latter style would force duplicate error 
handling with promises: it would not. Very similar to sync code, you would write

```js
userAllowsNotifications().then(canNotify = {
  if (canNotify) {
var data = prepareNotificationData();
showNotification(data);
removeFromNotificationQueue(data);
  }
});
```

and any other errors (e.g. programming errors, like if someone had typo'd 
prepareNotificationData()) would flow up to the developer tools, and eventually 
to window.onerror or similar once we get that specced [1]. You would not write 
an explicit `.catch(...)` to handle such failures.

(And yes, only Firefox's developer tools correctly show such errors; Chrome is 
embarrassingly behind in that regard.)

---

Bringing this back to requestPermission() and notifications: honestly, the name 
doesn't help me much in deciding which programming model we want. It could go 
either way.

So we should make a choice, as to whether we want developers to assume they 
will always get permission (in which case it should reject upon permission not 
being granted), or whether we want developers to ask the API whether they were 
granted permission (in which case it should give back a boolean fulfillment 
value or similar).


[1]: http://lists.w3.org/Archives/Public/public-whatwg-archive/2014Sep/0024.html


[whatwg] Notifications: making requestPermission() return a promise

2014-10-01 Thread Anne van Kesteren
On Wed, Oct 1, 2014 at 2:56 PM, Peter Beverloo bever...@google.com wrote:
 One argument I came across for overloading requestPermission is the
 following:
 Promise.all([ Notification.requestPermission(),
 swRegistration.push.requestPermission() ]).then(...);

 Might be worth considering, it's relatively cheap to support and can be
 implemented without breaking backwards compatibility.

One minor risk with also returning a promise is that exceptions for
incorrect invocation would no longer throw an exception, but instead
reject the promise.

Otherwise I would never expect this promise to be rejected as the user
declining notifications is not exceptional.

I would be okay with adding this.


-- 
https://annevankesteren.nl/


Re: [whatwg] Notifications: making requestPermission() return a promise

2014-10-01 Thread Tab Atkins Jr.
On Wed, Oct 1, 2014 at 9:06 AM, Anne van Kesteren ann...@annevk.nl wrote:
 On Wed, Oct 1, 2014 at 2:56 PM, Peter Beverloo bever...@google.com wrote:
 One argument I came across for overloading requestPermission is the
 following:
 Promise.all([ Notification.requestPermission(),
 swRegistration.push.requestPermission() ]).then(...);

 Might be worth considering, it's relatively cheap to support and can be
 implemented without breaking backwards compatibility.

 One minor risk with also returning a promise is that exceptions for
 incorrect invocation would no longer throw an exception, but instead
 reject the promise.

 Otherwise I would never expect this promise to be rejected as the user
 declining notifications is not exceptional.

Wait, what?  Anytime you request something, not getting it is
exceptional.  Not sure how you can make an argument otherwise.

~TJ


Re: [whatwg] Notifications: making requestPermission() return a promise

2014-10-01 Thread Anne van Kesteren
On Wed, Oct 1, 2014 at 3:14 PM, Tab Atkins Jr. jackalm...@gmail.com wrote:
 Wait, what?  Anytime you request something, not getting it is
 exceptional.  Not sure how you can make an argument otherwise.

I would not expect a synchronous version of this method (were it to
exist) to have to use try/catch for anything other than invoking it
with an argument such as TEST, which is clearly wrong. That's why I
don't think it's exceptional (e.g. warrants an exception/rejection).


-- 
https://annevankesteren.nl/


Re: [whatwg] Notifications: making requestPermission() return a promise

2014-10-01 Thread Tab Atkins Jr.
On Wed, Oct 1, 2014 at 9:18 AM, Anne van Kesteren ann...@annevk.nl wrote:
 On Wed, Oct 1, 2014 at 3:14 PM, Tab Atkins Jr. jackalm...@gmail.com wrote:
 Wait, what?  Anytime you request something, not getting it is
 exceptional.  Not sure how you can make an argument otherwise.

 I would not expect a synchronous version of this method (were it to
 exist) to have to use try/catch for anything other than invoking it
 with an argument such as TEST, which is clearly wrong. That's why I
 don't think it's exceptional (e.g. warrants an exception/rejection).

And I wouldn't expect someone loading a FontFace synchronously to use
try/catch to deal with loading errors, either, because that's super
obnoxious.  Failure, though, is a standard rejection reason - it maps
to the use of onerror events.

Without it, the promise algebra functions become far less useful, and
you have to type-test the fulfillment value to see if it's actually
the value you want, or some sort of proxy that communicates failure.

~TJ


Re: [whatwg] Notifications: making requestPermission() return a promise

2014-10-01 Thread James Graham
On 01/10/14 14:21, Tab Atkins Jr. wrote:
 On Wed, Oct 1, 2014 at 9:18 AM, Anne van Kesteren ann...@annevk.nl wrote:
 On Wed, Oct 1, 2014 at 3:14 PM, Tab Atkins Jr. jackalm...@gmail.com wrote:
 Wait, what?  Anytime you request something, not getting it is
 exceptional.  Not sure how you can make an argument otherwise.

 I would not expect a synchronous version of this method (were it to
 exist) to have to use try/catch for anything other than invoking it
 with an argument such as TEST, which is clearly wrong. That's why I
 don't think it's exceptional (e.g. warrants an exception/rejection).
 
 And I wouldn't expect someone loading a FontFace synchronously to use
 try/catch to deal with loading errors, either, because that's super
 obnoxious.  Failure, though, is a standard rejection reason - it maps
 to the use of onerror events.

Isn't this just a problem that we have three possible outcomes:

* Permission grant

* Permission reject

* Invalid input data

And three possible ways of routing the code:

* Promise fulfilled

* Promise rejected

* Exception

But we are only using two of them? In that case something has to give;
you either need to disambiguate user grant vs user reject in the fulfill
function or user reject vs invalid data in the rejection function.
Neither seems obviously to have better ergonomics than the other.


Re: [whatwg] Notifications: making requestPermission() return a promise

2014-10-01 Thread Anne van Kesteren
On Wed, Oct 1, 2014 at 3:21 PM, Tab Atkins Jr. jackalm...@gmail.com wrote:
 And I wouldn't expect someone loading a FontFace synchronously to use
 try/catch to deal with loading errors, either, because that's super
 obnoxious.  Failure, though, is a standard rejection reason - it maps
 to the use of onerror events.

 Without it, the promise algebra functions become far less useful, and
 you have to type-test the fulfillment value to see if it's actually
 the value you want, or some sort of proxy that communicates failure.

Once we have async/await syntax the synchronous version is what you
get. I would not want try/catch for requestPermission() there. As far
as I know promises are just like functions in that regard, you only
want to reject/throw if you want to force try/catch on the user.


-- 
https://annevankesteren.nl/


Re: [whatwg] Notifications: making requestPermission() return a promise

2014-10-01 Thread Tab Atkins Jr.
On Wed, Oct 1, 2014 at 9:34 AM, Anne van Kesteren ann...@annevk.nl wrote:
 On Wed, Oct 1, 2014 at 3:21 PM, Tab Atkins Jr. jackalm...@gmail.com wrote:
 And I wouldn't expect someone loading a FontFace synchronously to use
 try/catch to deal with loading errors, either, because that's super
 obnoxious.  Failure, though, is a standard rejection reason - it maps
 to the use of onerror events.

 Without it, the promise algebra functions become far less useful, and
 you have to type-test the fulfillment value to see if it's actually
 the value you want, or some sort of proxy that communicates failure.

 Once we have async/await syntax the synchronous version is what you
 get. I would not want try/catch for requestPermission() there. As far
 as I know promises are just like functions in that regard, you only
 want to reject/throw if you want to force try/catch on the user.

Yeah, this is a mismatch of expectations based on how you use it.

If you're using Promises, and the promise algebra like .all() or
.race(), you expect only success to result in fulfillment; failure
should reject, so you can specialize your code paths properly and have
the algebra work well.  I want to be able to use Promise.all() on
several permission requests to tell if I get them all; if they always
fulfill, Promise.all() becomes solely a synchronization primitive, not
a useful value algebra operation.

If you're using async/await to hide the asynchrony, you only want
error situations to throw, because dealing with throwing is really
annoying.

This is actually kinda terrible.  Promises make it *really easy* to
deal with rejections *later*, letting you execute a bunch of code on
the success path and only at the end saying Oh, did something along
the line fail? Let me take care of that..  Promise is basically an
async Maybe monad, which is great, because Maybe is useful for
*exactly the scenario I just outlined*.

Changing things so that you have to go back to wrapping all your code
in try/catch (and not just the one call - if you're chaining promises,
they *all* have to be wrapped) is kinda terrible, and distorts the
ergonomics of the system.  What was once great, when done directly
with Promises, is now terrible, when done with async/await; you're
forced to pay for that convenience!

I think we should develop Promises in a way that exploits their
ergonomics properly, and then rethink async/await a bit to make it
match those ergonomics, rather than fighting them.

~TJ


Re: [whatwg] Notifications: making requestPermission() return a promise

2014-10-01 Thread Domenic Denicola
From: whatwg [mailto:whatwg-boun...@lists.whatwg.org] On Behalf Of Tab Atkins 
Jr.

 This is actually kinda terrible.  Promises make it *really easy* to deal with 
 rejections *later*, letting you execute a bunch of code on the success path 
 and only at the end saying Oh, did something along the line fail? Let me 
 take care of that..  Promise is basically an async Maybe monad, which is 
 great, because Maybe is useful for *exactly the scenario I just outlined*.

This is exactly the wrong way to think about promises. Promises are the async 
return/throw monad; if you want a Maybe, then you have to compose that in 
yourself. People often try to abuse the fact that they have a second branch for 
exceptions in order to use it as a generic container for go down two possible 
flow paths, but that is very incorrect. An earlier comment in the thread about 
we have three possible mechanisms is also symptomatic of this incorrect 
thinking. We have two mechanisms: return and throw. When you wrap those in 
async, they become fulfill and reject.

 I think we should develop Promises in a way that exploits their ergonomics 
 properly, and then rethink async/await a bit to make it match those 
 ergonomics, rather than fighting them.

We are not changing the model of promises in this way. If you want a Maybe 
monad, that's a separate API that you'd want to spec.



Re: [whatwg] Notifications: making requestPermission() return a promise

2014-10-01 Thread Jeffrey Yasskin
On Wed, Oct 1, 2014 at 6:06 AM, Anne van Kesteren ann...@annevk.nl wrote:
 On Wed, Oct 1, 2014 at 2:56 PM, Peter Beverloo bever...@google.com wrote:
 One argument I came across for overloading requestPermission is the
 following:
 Promise.all([ Notification.requestPermission(),
 swRegistration.push.requestPermission() ]).then(...);

 Might be worth considering, it's relatively cheap to support and can be
 implemented without breaking backwards compatibility.

 One minor risk with also returning a promise is that exceptions for
 incorrect invocation would no longer throw an exception, but instead
 reject the promise.

 Otherwise I would never expect this promise to be rejected as the user
 declining notifications is not exceptional.

On a distributed system, a network error isn't unusual either, but it
still makes sense to treat it as an exception because the
application's main codepath can't continue executing. Similarly, if a
permission the application expects isn't granted, the application has
to skip the rest of its main codepath, so it makes sense to treat that
as an exception too.

If Tab wants to avoid try/catch blocks around most of his code, he can
simply avoid using await for those promises, and transform their
values with .catch(), but exceptions are really the same thing as
«deal with rejections *later*, letting you execute a bunch of code on
the success path and only at the end saying Oh, did something along
the line fail? Let me take care of that..»


Re: [whatwg] Notifications: making requestPermission() return a promise

2014-10-01 Thread Tab Atkins Jr.
On Wed, Oct 1, 2014 at 11:44 AM, Domenic Denicola
dome...@domenicdenicola.com wrote:
 From: whatwg [mailto:whatwg-boun...@lists.whatwg.org] On Behalf Of Tab Atkins 
 Jr.

 This is actually kinda terrible.  Promises make it *really easy* to deal 
 with rejections *later*, letting you execute a bunch of code on the success 
 path and only at the end saying Oh, did something along the line fail? Let 
 me take care of that..  Promise is basically an async Maybe monad, which is 
 great, because Maybe is useful for *exactly the scenario I just outlined*.

 This is exactly the wrong way to think about promises. Promises are the 
 async return/throw monad; if you want a Maybe, then you have to compose 
 that in yourself. People often try to abuse the fact that they have a second 
 branch for exceptions in order to use it as a generic container for go down 
 two possible flow paths, but that is very incorrect. An earlier comment in 
 the thread about we have three possible mechanisms is also symptomatic of 
 this incorrect thinking. We have two mechanisms: return and throw. When you 
 wrap those in async, they become fulfill and reject.

 I think we should develop Promises in a way that exploits their ergonomics 
 properly, and then rethink async/await a bit to make it match those 
 ergonomics, rather than fighting them.

 We are not changing the model of promises in this way. If you want a Maybe 
 monad, that's a separate API that you'd want to spec.

I've never heard this opinion explicitly expressed, and it has never
shown up in any API reviews of promise-using specs.  It's directly
contrary to the way that existing non-promise async APIs are
constructed, and I expect quite contrary to most people's
expectations.

Geo, for example, throws if you pass bad arguments, but then routes
its result through either a success or error callback.  This is
*directly* analogous to the signature of Promise.then(), and I think a
lot of people would expect a getCurrentPosition() that returned a
promise would have the same behavior.  This allows you to just assume
that the value passed to the success callback is a position, and write
code accordingly.

It feels like your position leads directly to the error handling in
two places problem that you, I, and others railed against in the
promise-returning functions should never throw debate.  You have to
handle bad arguments in the reject callback to the promise, and handle
failure in the fulfill callback.  It'll lead to a ton of boilerplate
`if(arg == null) throw;` at the top of fulfill callbacks, so that the
fulfill chain is *actually for the successful case*.

~TJ


Re: [whatwg] Notifications: making requestPermission() return a promise

2014-10-01 Thread Tab Atkins Jr.
On Wed, Oct 1, 2014 at 11:52 AM, Jeffrey Yasskin jyass...@chromium.org wrote:
 On Wed, Oct 1, 2014 at 6:06 AM, Anne van Kesteren ann...@annevk.nl wrote:
 On Wed, Oct 1, 2014 at 2:56 PM, Peter Beverloo bever...@google.com wrote:
 One argument I came across for overloading requestPermission is the
 following:
 Promise.all([ Notification.requestPermission(),
 swRegistration.push.requestPermission() ]).then(...);

 Might be worth considering, it's relatively cheap to support and can be
 implemented without breaking backwards compatibility.

 One minor risk with also returning a promise is that exceptions for
 incorrect invocation would no longer throw an exception, but instead
 reject the promise.

 Otherwise I would never expect this promise to be rejected as the user
 declining notifications is not exceptional.

 On a distributed system, a network error isn't unusual either, but it
 still makes sense to treat it as an exception because the
 application's main codepath can't continue executing. Similarly, if a
 permission the application expects isn't granted, the application has
 to skip the rest of its main codepath, so it makes sense to treat that
 as an exception too.

Precisely.

 If Tab wants to avoid try/catch blocks around most of his code, he can
 simply avoid using await for those promises, and transform their
 values with .catch(), but exceptions are really the same thing as
 «deal with rejections *later*, letting you execute a bunch of code on
 the success path and only at the end saying Oh, did something along
 the line fail? Let me take care of that..»

Yeah, you're right.  try/catch is just more annoying to use than a
.catch() at the end of a promise chain. ^_^

On Wed, Oct 1, 2014 at 11:34 AM, Tab Atkins Jr. jackalm...@gmail.com wrote:
 I think we should develop Promises in a way that exploits their
 ergonomics properly, and then rethink async/await a bit to make it
 match those ergonomics, rather than fighting them.

For example, we could have *two* keywords for awaiting - one that
throws all rejections, and one that converts non-fatal errors
(tagged in the exception somehow) into fulfills for you automatically.
Or a method on Promise.prototype that does the same.  That way a
permission rejection can reject a promise usefully (letting you count
on the success path as meaning I got permission), and someone can
still, if they wish, handle no-permission in their normal code path
and leave errors for actual coding errors.

~TJ


Re: [whatwg] Notifications: making requestPermission() return a promise

2014-10-01 Thread Tobie Langel
On Wed, Oct 1, 2014 at 5:59 PM, Tab Atkins Jr. jackalm...@gmail.com wrote:

 I've never heard this opinion explicitly expressed, and it has never
 shown up in any API reviews of promise-using specs.  It's directly
 contrary to the way that existing non-promise async APIs are
 constructed, and I expect quite contrary to most people's
 expectations.


I'm with Domenic, here. We had these conversations for the Service Worker
Cache's .match() method and dropped promise rejection in favor of resolving
with null when a relevant Response object couldn't be found in the cache.
Rejecting the promise was left for truly exceptional cases, such a data
corruption issues.

I agree with you that the code branching provided by the resolve/reject
pair looks appealing at first, but it's terrible once awaits comes in the
picture.


Re: [whatwg] Notifications: making requestPermission() return a promise

2014-10-01 Thread Tab Atkins Jr.
On Wed, Oct 1, 2014 at 1:02 PM, Tobie Langel tobie.lan...@gmail.com wrote:
 On Wed, Oct 1, 2014 at 5:59 PM, Tab Atkins Jr. jackalm...@gmail.com wrote:
 I've never heard this opinion explicitly expressed, and it has never
 shown up in any API reviews of promise-using specs.  It's directly
 contrary to the way that existing non-promise async APIs are
 constructed, and I expect quite contrary to most people's
 expectations.

 I'm with Domenic, here. We had these conversations for the Service Worker
 Cache's .match() method and dropped promise rejection in favor of resolving
 with null when a relevant Response object couldn't be found in the cache.
 Rejecting the promise was left for truly exceptional cases, such a data
 corruption issues.

 I agree with you that the code branching provided by the resolve/reject pair
 looks appealing at first, but it's terrible once awaits comes in the
 picture.

Wow, that's kinda terrible.  The operation literally failed; there is
no way in which it could be said to have succeeded, and you absolutely
want to run different code paths based on whether it succeeded or
failed.  Instead, you are forced to either run your failure-path code
in the fulfill callback alongside the success-path code, or do what I
said upthread and add a `if(arg == null) throw` line to the top of
your fulfill callback so you can treat the fulfill callbacks as always
succeeding.

Note that Python, for example, throws errors on dict keys not being
found (unless you specifically tell it a sentinel value to return
instead).  Do you think that's terrible?

This sort of behavior makes promise rejection essentially worthless.
You can't base anything off of whether a promise fulfilled or not,
because it'll only fail for weird exceptional cases; most of your
failures (cases where the thing you were asking for couldn't be
done) are instead mixed into your fulfill channel.

~TJ


Re: [whatwg] Notifications: making requestPermission() return a promise

2014-10-01 Thread Tobie Langel
On Wed, Oct 1, 2014 at 7:22 PM, Tab Atkins Jr. jackalm...@gmail.com wrote:

 Note that Python, for example, throws errors on dict keys not being
 found (unless you specifically tell it a sentinel value to return
 instead).  Do you think that's terrible?


Sure. But JS doesn't.


Re: [whatwg] Notifications: making requestPermission() return a promise

2014-10-01 Thread Domenic Denicola




 On Oct 1, 2014, at 16:59, Tab Atkins Jr. jackalm...@gmail.com wrote:
 
 On Wed, Oct 1, 2014 at 11:44 AM, Domenic Denicola
 dome...@domenicdenicola.com wrote:
 From: whatwg [mailto:whatwg-boun...@lists.whatwg.org] On Behalf Of Tab 
 Atkins Jr.
 
 This is actually kinda terrible.  Promises make it *really easy* to deal 
 with rejections *later*, letting you execute a bunch of code on the success 
 path and only at the end saying Oh, did something along the line fail? Let 
 me take care of that..  Promise is basically an async Maybe monad, which 
 is great, because Maybe is useful for *exactly the scenario I just 
 outlined*.
 
 This is exactly the wrong way to think about promises. Promises are the 
 async return/throw monad; if you want a Maybe, then you have to compose 
 that in yourself. People often try to abuse the fact that they have a second 
 branch for exceptions in order to use it as a generic container for go down 
 two possible flow paths, but that is very incorrect. An earlier comment in 
 the thread about we have three possible mechanisms is also symptomatic of 
 this incorrect thinking. We have two mechanisms: return and throw. When you 
 wrap those in async, they become fulfill and reject.
 
 I think we should develop Promises in a way that exploits their ergonomics 
 properly, and then rethink async/await a bit to make it match those 
 ergonomics, rather than fighting them.
 
 We are not changing the model of promises in this way. If you want a Maybe 
 monad, that's a separate API that you'd want to spec.
 
 I've never heard this opinion explicitly expressed,

http://domenic.me/2012/10/14/youre-missing-the-point-of-promises/
http://www.w3.org/2001/tag/doc/promises-guide#rejections-should-be-exceptional

 and it has never
 shown up in any API reviews of promise-using specs.  It's directly
 contrary to the way that existing non-promise async APIs are
 constructed, and I expect quite contrary to most people's
 expectations.
 
 Geo, for example, throws if you pass bad arguments, but then routes
 its result through either a success or error callback.  This is
 *directly* analogous to the signature of Promise.then(), and I think a
 lot of people would expect a getCurrentPosition() that returned a
 promise would have the same behavior.  This allows you to just assume
 that the value passed to the success callback is a position, and write
 code accordingly.
 
 It feels like your position leads directly to the error handling in
 two places problem that you, I, and others railed against in the
 promise-returning functions should never throw debate.  You have to
 handle bad arguments in the reject callback to the promise, and handle
 failure in the fulfill callback.  It'll lead to a ton of boilerplate
 `if(arg == null) throw;` at the top of fulfill callbacks, so that the
 fulfill chain is *actually for the successful case*.
 
 ~TJ


Re: [whatwg] Notifications: making requestPermission() return a promise

2014-10-01 Thread Domenic Denicola




 On Oct 1, 2014, at 18:22, Tab Atkins Jr. jackalm...@gmail.com wrote:
 
 On Wed, Oct 1, 2014 at 1:02 PM, Tobie Langel tobie.lan...@gmail.com wrote:
 On Wed, Oct 1, 2014 at 5:59 PM, Tab Atkins Jr. jackalm...@gmail.com wrote:
 I've never heard this opinion explicitly expressed, and it has never
 shown up in any API reviews of promise-using specs.  It's directly
 contrary to the way that existing non-promise async APIs are
 constructed, and I expect quite contrary to most people's
 expectations.
 
 I'm with Domenic, here. We had these conversations for the Service Worker
 Cache's .match() method and dropped promise rejection in favor of resolving
 with null when a relevant Response object couldn't be found in the cache.
 Rejecting the promise was left for truly exceptional cases, such a data
 corruption issues.
 
 I agree with you that the code branching provided by the resolve/reject pair
 looks appealing at first, but it's terrible once awaits comes in the
 picture.
 
 Wow, that's kinda terrible.  The operation literally failed; there is
 no way in which it could be said to have succeeded, and you absolutely
 want to run different code paths based on whether it succeeded or
 failed.  Instead, you are forced to either run your failure-path code
 in the fulfill callback alongside the success-path code, or do what I
 said upthread and add a `if(arg == null) throw` line to the top of
 your fulfill callback so you can treat the fulfill callbacks as always
 succeeding.
 
 Note that Python, for example, throws errors on dict keys not being
 found (unless you specifically tell it a sentinel value to return
 instead).  Do you think that's terrible?
 
 This sort of behavior makes promise rejection essentially worthless.

They are as worthless as exceptions.

 You can't base anything off of whether a promise fulfilled or not,
 because it'll only fail for weird exceptional cases; most of your
 failures (cases where the thing you were asking for couldn't be
 done) are instead mixed into your fulfill channel.
 
 ~TJ


Re: [whatwg] Notifications: making requestPermission() return a promise

2014-10-01 Thread David Dorwin
On Wed, Oct 1, 2014 at 10:53 AM, Domenic Denicola 
dome...@domenicdenicola.com wrote:





  On Oct 1, 2014, at 18:22, Tab Atkins Jr. jackalm...@gmail.com wrote:
 
  On Wed, Oct 1, 2014 at 1:02 PM, Tobie Langel tobie.lan...@gmail.com
 wrote:
  On Wed, Oct 1, 2014 at 5:59 PM, Tab Atkins Jr. jackalm...@gmail.com
 wrote:
  I've never heard this opinion explicitly expressed, and it has never
  shown up in any API reviews of promise-using specs.  It's directly
  contrary to the way that existing non-promise async APIs are
  constructed, and I expect quite contrary to most people's
  expectations.
 
  I'm with Domenic, here. We had these conversations for the Service
 Worker
  Cache's .match() method and dropped promise rejection in favor of
 resolving
  with null when a relevant Response object couldn't be found in the
 cache.
  Rejecting the promise was left for truly exceptional cases, such a data
  corruption issues.
 
  I agree with you that the code branching provided by the resolve/reject
 pair
  looks appealing at first, but it's terrible once awaits comes in the
  picture.
 
  Wow, that's kinda terrible.  The operation literally failed; there is
  no way in which it could be said to have succeeded, and you absolutely
  want to run different code paths based on whether it succeeded or
  failed.  Instead, you are forced to either run your failure-path code
  in the fulfill callback alongside the success-path code, or do what I
  said upthread and add a `if(arg == null) throw` line to the top of
  your fulfill callback so you can treat the fulfill callbacks as always
  succeeding.
 
  Note that Python, for example, throws errors on dict keys not being
  found (unless you specifically tell it a sentinel value to return
  instead).  Do you think that's terrible?
 
  This sort of behavior makes promise rejection essentially worthless.

 They are as worthless as exceptions.

  You can't base anything off of whether a promise fulfilled or not,
  because it'll only fail for weird exceptional cases; most of your
  failures (cases where the thing you were asking for couldn't be
  done) are instead mixed into your fulfill channel.


This is especially true if you wanted to try a series of calls (i.e.
supported media features). If the resolve function is only called on
success (i.e. supported and usable), then the rejection path can try the
next prefered option. If valid-call-but-not-supported is reported to the
resolve function and input-is-somehow-invalid-for-this-ua is reported as a
rejection, an application needs to call the try next logic in both branches.

Rejection also has the advantage of providing an exception, which can
provide information (reason and message) to differentiate between
potentially multiple causes. This is not possible when resolving with null.
Providing such information would likely make development and debugging
easier.

 
  ~TJ



Re: [whatwg] Notifications: making requestPermission() return a promise

2014-10-01 Thread Boris Zbarsky

On 10/1/14, 1:59 PM, David Dorwin wrote:

Rejection also has the advantage of providing an exception, which can
provide information (reason and message) to differentiate between
potentially multiple causes. This is not possible when resolving with null.
Providing such information would likely make development and debugging
easier.


If you were designing a sync API, would not the same arguments apply? 
So you'd want to throw different kinds of exceptions to indicate not 
supported?


-Boris



Re: [whatwg] Notifications: making requestPermission() return a promise

2014-10-01 Thread David Dorwin
On Wed, Oct 1, 2014 at 11:02 AM, Boris Zbarsky bzbar...@mit.edu wrote:

 On 10/1/14, 1:59 PM, David Dorwin wrote:

 Rejection also has the advantage of providing an exception, which can
 provide information (reason and message) to differentiate between
 potentially multiple causes. This is not possible when resolving with
 null.
 Providing such information would likely make development and debugging
 easier.


 If you were designing a sync API, would not the same arguments apply? So
 you'd want to throw different kinds of exceptions to indicate not
 supported?


I would specify that DOMException with the name NotSupportedError be
thrown. User agent implementations could provide more information in the
message. (There might be other non-exceptional failures that would use
different exception names.)

However, it sounds like something not being supported by a UA would not be
exceptional, so an exception should not be thrown in this case. (This is
no less expected than the user
declining notifications.) I guess the synchronous API would return null.
That seems odd since an exception has historically been thrown in such
cases.



 -Boris




Re: [whatwg] Notifications: making requestPermission() return a promise

2014-10-01 Thread Anne van Kesteren
On Wed, Oct 1, 2014 at 8:30 PM, David Dorwin ddor...@chromium.org wrote:
 I would specify that DOMException with the name NotSupportedError be
 thrown. User agent implementations could provide more information in the
 message. (There might be other non-exceptional failures that would use
 different exception names.)

We typically use non-throwing mechanism for unsupported features. E.g.
properties that accept enumerations that when set to an unknown
enumeration don't change. From experience, this tends to break pages
less in user agents not offering certain features. This is also why
XMLHttpRequest evolved to throw less exceptions over time.

However, that seems like a bit of a digression from the main issue
here. Which is whether promises-returning methods should be modeled
after functions (return/throw) or have some kind of alternative
design. Given async/await the only reasonable thing to do seems to me
to model them after functions and only use rejection for something
exceptional, but with the level of disagreement this has created in
several different standards group thus far, I'm not hopeful initial
promise APIs will be consistent in this.


-- 
https://annevankesteren.nl/


Re: [whatwg] Notifications: making requestPermission() return a promise

2014-10-01 Thread Tobie Langel
On Wed, Oct 1, 2014 at 11:43 PM, Anne van Kesteren ann...@annevk.nl wrote:

 Given async/await the only reasonable thing to do seems to me
 to model them after functions and only use rejection for something
 exceptional, but with the level of disagreement this has created in
 several different standards group thus far, I'm not hopeful initial
 promise APIs will be consistent in this.


If that's not work for the TAG, then I don't know what their purpose is.
Seriously, there needs to be agreement and consistency here, and unless
there a design guidelines adopted across the board, this is just going to
suck for Web developers.

--tobie


Re: [whatwg] Notifications: making requestPermission() return a promise

2014-10-01 Thread Ian Hickson
On Wed, 1 Oct 2014, Domenic Denicola wrote:
  
  This sort of behavior makes promise rejection essentially worthless.
 
 They are as worthless as exceptions.

Some exceptions _are_ worthless, as witnessed by the fact that nobody 
ever tries to catch them. For example, TypeError.

This is why I've argued before that these worthless exceptions should 
continue to be real exceptions even in the Promise case.

Incidentally, this bug and this comment in particular are quite relevant 
to this thread (regarding how to design an API with promises):

   https://www.w3.org/Bugs/Public/show_bug.cgi?id=25472#c18

-- 
Ian Hickson   U+1047E)\._.,--,'``.fL
http://ln.hixie.ch/   U+263A/,   _.. \   _\  ;`._ ,.
Things that are impossible just take longer.   `._.-(,_..'--(,_..'`-.;.'