You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Mar 25, 2018. It is now read-only.
Repository navigation
This repository was archived by the owner on Mar 25, 2018. It is now read-only.
I'm not sure the multiple-return from await is necessary – as I understand the async/await proposal, if a promise rejects it bubbles back to the caller as an exception:
Yes, I think @vkurchatkin is suggesting abandoning exceptions and error bubbling in favor of multi-value return (like Go, IIUC). So the promise returned would always fulfill, and would fulfill with a [err, res] tuple.
I don't like it, as I think exceptions and error bubbling add a lot to programming in general. But I know there are many who disagree with me there.
@domenic right, inspired by Go mostly. It's basically exceptions vs errors. Exceptions are invalid input, etc. If one wants an error to bubble they can explicitly rethrow it.
I don't like it, as I think exceptions and error bubbling add a lot to programming in general.
I agree. They can be kind of a mess in C++, but in garbage-collected languages they're pretty nice. Manually handling every error at the callsite makes it hard to group errors naturally, easy to forget to handle them, and arduous to get the errors back to code that can usefully handle them. In short, it's exactly what we have now with node style callbacks, and a big part of what Promises would make better :)
The main issue with try/catch exception handling is that it only allows you to deal with a problem once it had turned catastrophic. The stack is gone, all the execution context is blown out, and the best you can do is work with the serialization to figure out what happened. Literally anything you can do is better than that, in that anything else you could do would allow you to work with a problem in the course of failing rather than after it has failed catastrophically.
The main issue with try/catch exception handling is that it only allows you to deal with a problem once it had turned catastrophic. The stack is gone, all the execution context is blown out, and the best you can do is work with the serialization to figure out what happened. Literally anything you can do is better than that, in that anything else you could do would allow you to work with a problem in the course of failing rather than after it has failed catastrophically.
I don't see why any of that is true... In the cases we're discussing here, they're isomorphic.
I agree it should be exceptions, never return values, for reasons outlined in http://yosefk.com/blog/error-codes-vs-exceptions-critical-code-vs-typical-code.html. However the language constructs when using async/await are insufficient, it will need a typed and/or predicated catch statement and a using (C#)/try-with-resources(Java)/ with(python) statement.
The main issue with try/catch exception handling is that it only allows you to deal with a problem once it had turned catastrophic.
There is no difference between error codes and exceptions WRT to this, you can try catch any call just like you can check the error code of any call. But since you are only going to propagate the error to the caller anyway, automatic propagation of exceptions is very nice and you don't need the try catch.
However the language constructs when using async/await are insufficient […]
In my personal experience this is incredibly true. Even if it’s now out of the spec, _CancellationError_s are very difficult to manage in ES2015 co+yield code.
In my personal experience this is incredibly true. Even if it’s now out of the spec, CancellationErrors are very difficult to manage in ES2015 co+yield code.
cancellation can be managed via runners like co if they were to use generators' .return method, I use it for aborts/cancellation in https://github.com/bmeck/generator-runner. There are open issues in the spec to support cancellation via async functions, but they are not fleshed out yet. Though, I almost never use catch {} almost only finally {} now days, let the errors bubble!
@benjamingr I don't think that conditional catch is a good idea in a dynamically typed language.
For what it's worth, almost every other dynamic language has it (e.g. Python) and people use it all the time. In addition, it could be a predicate - but I just wanted to give an example of how I'd deal with it.
People have been using promises with async/await, Node and Babel for years now. The whole reason the TC added async/awaic is to enable people to write code this way - otherwise we'd just stick with generators.
If I wrap all the code or write it myself I can treat rejections as programmer errors and let them bubble.
Promise rejections do not only symbolize programmer errors. This is fundamental and goes to the mental model of promises - it's what they do conceptually. Promises were born to serve as proxies for values - rejections symbolize regular exceptions and regular exceptions are not always programmer errors in the JavaScript language.
Even things that are not programmer errors you'd want to bubble - it is about ownership and control - very often you can't deal with the vast majority of errors - it is about responsibility and passing it on the same way returning passes it on. My readCSVFile method should not be in charge of what to do when the file is not there - that's why Node code is typically full of if(err) return cb(err) because the error is very often propagated manually and when it is not most of the times it is a mistake.
let[err,res]=awaitasyncOperation();if(!err&&res!=null){// do stuff}
How is this better than callbacks or throwing?
Maybe I miss something, but can someone make an example with more than 1 line of code, control flow etc. ?
A good way to reason about exceptions and organize EH code is to follow the contract metaphor:
every function that you write implements some kind of contract
if the contract succeeds, the function returns normally.
if the contract cannot be fulfilled the function throws.
If f1 calls f2, f3 and f4, and if f3 cannot fulfill its contract, then most of the time f1 will not be able to fulfill its own contract either. So the best it can do is fail (throw). Catching locally does not help (try { f3(); } catch (ex) { throw ex; } is just plain silly).
There are a few places in an application where contracts get looser. In these functions you can catch exceptions and still satisfy the contract. A typical example is a top level HTTP request dispatcher. At this level the contract becomes very loose and very generic; something like: "dispatch the request and return an HTTP response, either a success one (2xx, 3xx) or an error one (4xx, 5xx)". This is the right place to catch and returnnormally.
You also need to be careful about releasing resources and restoring program invariants but that's where try/finally comes to the rescue.
These classical EH patterns had become unusable in callback code because exception bubbling goes to the event loop instead of the logical caller. Async/await restores them.
@YuriSolovyov
Most of the time you would end up with:
let[err,res]=awaitasyncOperation();if(err)throwerr;// reject my own promise - what else can I do??// do stuff
Instead, you should just write:
letres=awaitasyncOperation();// do stuff.
There is also the fact that error codes get in the way. They force you to decompose any expression that contains async calls. With error codes, you cannot write something as simple as:
letres=syncOp(awaitasyncOp());
Exceptions allow you to clearly separate the EH code. Your logic is not broken / polluted by error checks, and you can review the exception handling logic separately.
Activity
chrisdickinson commentedon Mar 2, 2015
I'm not sure the multiple-return from
awaitis necessary – as I understand the async/await proposal, if a promise rejects it bubbles back to the caller as an exception:cc'ing @domenic who knows more about this than I do :)
domenic commentedon Mar 2, 2015
Yes, I think @vkurchatkin is suggesting abandoning exceptions and error bubbling in favor of multi-value return (like Go, IIUC). So the promise returned would always fulfill, and would fulfill with a [err, res] tuple.
I don't like it, as I think exceptions and error bubbling add a lot to programming in general. But I know there are many who disagree with me there.
vkurchatkin commentedon Mar 2, 2015
@domenic right, inspired by Go mostly. It's basically exceptions vs errors. Exceptions are invalid input, etc. If one wants an error to bubble they can explicitly rethrow it.
chrisdickinson commentedon Mar 2, 2015
I agree. They can be kind of a mess in C++, but in garbage-collected languages they're pretty nice. Manually handling every error at the callsite makes it hard to group errors naturally, easy to forget to handle them, and arduous to get the errors back to code that can usefully handle them. In short, it's exactly what we have now with node style callbacks, and a big part of what Promises would make better :)
mikeal commentedon Mar 2, 2015
The main issue with try/catch exception handling is that it only allows you to deal with a problem once it had turned catastrophic. The stack is gone, all the execution context is blown out, and the best you can do is work with the serialization to figure out what happened. Literally anything you can do is better than that, in that anything else you could do would allow you to work with a problem in the course of failing rather than after it has failed catastrophically.
domenic commentedon Mar 3, 2015
I don't see why any of that is true... In the cases we're discussing here, they're isomorphic.
mikeal commentedon Mar 3, 2015
@domenic FYI, I edited your reply because the email support in GitHub flipped out for some reason. Please doublecheck to make sure it is correct.
domenic commentedon Mar 3, 2015
Yeah all good, thanks. #windowsphoneproblems
petkaantonov commentedon Mar 3, 2015
I agree it should be exceptions, never return values, for reasons outlined in http://yosefk.com/blog/error-codes-vs-exceptions-critical-code-vs-typical-code.html. However the language constructs when using async/await are insufficient, it will need a typed and/or predicated catch statement and a
using(C#)/try-with-resources(Java)/with(python) statement.There is no difference between error codes and exceptions WRT to this, you can try catch any call just like you can check the error code of any call. But since you are only going to propagate the error to the caller anyway, automatic propagation of exceptions is very nice and you don't need the try catch.
yuchi commentedon Mar 23, 2015
In my personal experience this is incredibly true. Even if it’s now out of the spec, _CancellationError_s are very difficult to manage in ES2015
co+yieldcode.bmeck commentedon Apr 7, 2015
cancellation can be managed via runners like
coif they were to use generators'.returnmethod, I use it for aborts/cancellation inhttps://github.com/bmeck/generator-runner. There are open issues in the spec to support cancellation via async functions, but they are not fleshed out yet. Though, I almost never usecatch {}almost onlyfinally {}now days, let the errors bubble!petkaantonov commentedon Apr 7, 2015
.return is not implemented anywhere
bmeck commentedon Apr 7, 2015
@petkaantonov I use regenerator which has it and firefox has it. Just because current v8 is not spec compliant does not mean we should ignore it.
xref v8 issue: https://code.google.com/p/v8/issues/detail?id=3566&q=generator%20return&colspec=ID%20Pri%20M%20Week%20ReleaseBlock%20Cr%20Status%20Owner%20Summary%20OS%20Modified
benjamingr commentedon Feb 14, 2016
Copying from nodejs/node#5020
@vkurchatkin
For what it's worth, almost every other dynamic language has it (e.g. Python) and people use it all the time. In addition, it could be a predicate - but I just wanted to give an example of how I'd deal with it.
People have been using promises with
async/await, Node and Babel for years now. The whole reason the TC added async/awaic is to enable people to write code this way - otherwise we'd just stick with generators.Promise rejections do not only symbolize programmer errors. This is fundamental and goes to the mental model of promises - it's what they do conceptually. Promises were born to serve as proxies for values - rejections symbolize regular exceptions and regular exceptions are not always programmer errors in the JavaScript language.
Even things that are not programmer errors you'd want to bubble - it is about ownership and control - very often you can't deal with the vast majority of errors - it is about responsibility and passing it on the same way
returning passes it on. MyreadCSVFilemethod should not be in charge of what to do when the file is not there - that's why Node code is typically full ofif(err) return cb(err)because the error is very often propagated manually and when it is not most of the times it is a mistake.YurySolovyov commentedon Feb 14, 2016
I wonder how examples from OP would evolve:
How is this better than callbacks or throwing?
Maybe I miss something, but can someone make an example with more than 1 line of code, control flow etc. ?
bjouhier commentedon Feb 14, 2016
Copying from nodejs/node#5020
@vkurchatkin
A good way to reason about exceptions and organize EH code is to follow the contract metaphor:
If
f1callsf2,f3andf4, and iff3cannot fulfill its contract, then most of the timef1will not be able to fulfill its own contract either. So the best it can do is fail (throw). Catching locally does not help (try { f3(); } catch (ex) { throw ex; }is just plain silly).There are a few places in an application where contracts get looser. In these functions you can catch exceptions and still satisfy the contract. A typical example is a top level HTTP request dispatcher. At this level the contract becomes very loose and very generic; something like: "dispatch the request and return an HTTP response, either a success one (2xx, 3xx) or an error one (4xx, 5xx)". This is the right place to
catchandreturnnormally.You also need to be careful about releasing resources and restoring program invariants but that's where
try/finallycomes to the rescue.These classical EH patterns had become unusable in callback code because exception bubbling goes to the event loop instead of the logical caller.
Async/awaitrestores them.bjouhier commentedon Feb 14, 2016
@YuriSolovyov
Most of the time you would end up with:
Instead, you should just write:
There is also the fact that error codes get in the way. They force you to decompose any expression that contains async calls. With error codes, you cannot write something as simple as:
Exceptions allow you to clearly separate the EH code. Your logic is not broken / polluted by error checks, and you can review the exception handling logic separately.
hax commentedon Mar 4, 2016
@petkaantonov FYI, I wrote a babel plugin to just patch
generator.prototype.returnfor V8.