Handling Errors in IcedCoffeeScript
maxtaco.github.io
maxtaco.github.io
---
malgorithms 22 hours ago | link
I think the great thing about IcedCoffeeScript + the ESC library is how it fits into more complicated flow logic, while allowing easy refactoring. Max doesn't really get into the otherwise impossible examples in his post.
Even if you're firing off RPC's awaiting in the middle of a loop or switch statement, you can move logic around just by shifting individual lines. Consider how simple this looks:
for user_id in user_ids
await load_user user_id, esc defer user
user.whatever()
# etc., with user
Writing that in plain Coffee or JS is impossible; using a pure async library is sort of possible but impossible to refactor. # serial
for uid, i in uids
await load_user uid, defer users[i]
All I do is move the await: # concurrent
await for uid, i in uids
load_user uid, defer users[i]
As you can imagine, this would be radically different JavaScript, yet it's (1) easy to read Coffee, (2) easy to refactor, and (3) runs on any browser.The ES6 stuff is new, and I can't use it because I'm writing for both Node and the browser, but can someone tell me how the above refactor would go?
something like
co(function *(){
for(i in uids){
users[i] = yield thunkify(load_users)(uids[i]);
}
});
While generators are useful, they dont make async code look like sync code.It takes a lot of getting used to but it is really, really nice to be able to surround error-prone code in what amounts to a try/catch, with a single catch that can (like Java) branch based on error type.
For a second it feels like sync programming.
As cool as ICS is, I strongly prefer the yield syntax to the await/defer syntax. It's a single keyword and it's much more obvious where the value is coming from. Plus, it's going to be everywhere soon.
At keybase, do you guys intend to continue with ICS or eventually move to ES6?
errTo = require 'errto'
readDirectoryAsync = (catalog, cb) ->
fs.readdir catalog, errTo cb, (filenames) -> # Notice no 'err' argument.
# Error check is done automatically in errTo and cb(err) is called on error.
# Subsequent code is called ONLY when no error given.
callback null, filenames
# Express sample.
app.get '/', (req, res, next) ->
readDirectoryAsync __dirname, errTo next, (filenames) -> # Use Express error handling by calling next(err)
res.send filenames
https://github.com/ashtuchkin/errto function *() {
try {
let body = yield request("https://x.io/");
return yield request("https://x.io/?q=" + body.hash);
} catch (e) {
// do what you like with the error
}
} ->
try
body = yield request "https://x.io/"
yield request "https://x.io/?q=#{body.hash}"
catch e
# do what you like with the error
... the salient bit being that there's no need to declare a generator function as a "special" type of function different from any other — a generator is simply a function that yields.