Live data from Hacker News

Escape from Callback Hell

ianbishop.github.com

21–30 of 86 posts

Re: Escape from Callback Hell

#21
post #16
post #3

It's a real shame to have a language this high level, yet still have to go through this much crap just to get things done. Manual memory management is easier than this. But while including GC in the runtime has it's drawbacks, there is no reason that a language can't just handle task switching for you (like Go does, for example).

IMHO the event model / callback spaghetti / what-have-you is tricky precisely because it operates at a high level of abstraction. Memory management, by comparison, is conceptually simpler because... well... the concept is simple. Allocating and de-allocating resources, while tricky at scale, is something for which everyone (including non-programmers) probably have existing mental models for. Event driven programming,…

You do event driven programming every time an alarm wakes you up or you set an egg timer.

Re: Escape from Callback Hell

#22
post #6
post #2

I honestly find "callback hell" a lot easier to follow and understand than the vast majority of fixes everyone is coming up with. They're just continuations, seriously, what's everyone's problem? You define a function, it gets access to the current scope, it defines the rest of the program flow. If you feel like your code is nesting too deep, you define the function elsewhere and just reference it by name. Then you d…

It's not difficult, it's just gross. And these promises don't solve the main problem, which is that synchronous functions return the result, until at some point you add some IO, so now it takes a callback. And everything that calls it now has to take a callback. And hours later all you've done is add a network call in some basic function but your diff looks like a total re-write.

This is an example of the "stack ripping" problem, described here (section 3.2): http://www.stanford.edu/class/cs240/readings/usenix2002-fibe...

Re: Escape from Callback Hell

#23
post #12
post #11

Deferreds are cool although they have their own set of issues. Mainly, that when you start chaining them there are situations where it can be a bit counterintuitive what is going on. My background is the Deferred from Twisted and Reimplemented in MochiKit. You really need to read the Deferred implementation if you are going to use it. Otherwise you are asking for trouble long term. Of course, the other issue is that…

Particularly Twisted's inlineCallbacks ( http://twistedmatrix.com/documents/current/api/twisted.inter... ) are really nice. They are so nice, they actually completely offset all the other unpleasantness I experiance from Twisted.

Yup thats what I was thinking of.

Re: Escape from Callback Hell

#25
post #2

I honestly find "callback hell" a lot easier to follow and understand than the vast majority of fixes everyone is coming up with. They're just continuations, seriously, what's everyone's problem? You define a function, it gets access to the current scope, it defines the rest of the program flow. If you feel like your code is nesting too deep, you define the function elsewhere and just reference it by name. Then you d…

I mostly agree, every time I see one of these I find trying to read it as a transformed version of the vanilla callback version is the easiest way to understand it. After all, when callbacks do get out of hand, approximating one of these is exactly how I end up dealing with it.

I wish `let` was a little different, syntactically. With something closer to what OCaml does, you don't need to surround everything in parens and braces. This would take all the visual grossness out of it (which I think is the biggest problem people really have):

    let (cb = function(x) { 
        ... 
    }) {
        foo(x,y,z,cb);
    }
vs.

    let cb = function(x) { 
        ... 
    } in
    foo(x,y,z,cb);
It doesn't look like much, but when you have a number of nested callbacks to define the latter syntax keeps everything on the same level where the former nests just as poorly as defining them in the parameter list. (I also hate seeing '})' anywhere, but not many people seem to care about that so much. It's why I switch to Monaco if I am doing JS.)

[Edit: formatting.]

Re: Escape from Callback Hell

#26
post #6

Earlier quoted context omitted.

It's not difficult, it's just gross. And these promises don't solve the main problem, which is that synchronous functions return the result, until at some point you add some IO, so now it takes a callback. And everything that calls it now has to take a callback. And hours later all you've done is add a network call in some basic function but your diff looks like a total re-write.

A function that doesn't do IO and a function that does IO sound like totally different functions to me. Why aren't you writing a new function?

That isnt the point, its that you have some nice code that does |var x = someBigFunction()| and at some point in the programs life, something inside someBigFunction turns async, you have a whole restructuring to do.

Re: Escape from Callback Hell

#27
I dont find that promises really help callback hell that much, they are useful but in the case of doing a series of sequential async functions the result is pretty similiar (the promises version is usually longer)

I got to write some firefox only code recently and added a delay to a function by just adding

   ... some code 
   setTimeout(continueFun, 5000)
   yield;
   ... more code
it felt like magic, I dont like generators and would much prefer to see message passing and blocking calls like erlang, but failing that it will be nice to be able to use generators more regularly

Re: Escape from Callback Hell

#28
post #6

Earlier quoted context omitted.

It's not difficult, it's just gross. And these promises don't solve the main problem, which is that synchronous functions return the result, until at some point you add some IO, so now it takes a callback. And everything that calls it now has to take a callback. And hours later all you've done is add a network call in some basic function but your diff looks like a total re-write.

A function that doesn't do IO and a function that does IO sound like totally different functions to me. Why aren't you writing a new function?

doing/not doing IO may be an implementation detail for a function. For example, say you have a function isPrime(x) that you implement using some primality test, with no IO. At some point in the future, you may notice that computing the primality test takes a long time, so instead you decide to submit the number to the server which will then return the answer. The function itself remains the same, it takes in a number and returns its primality, however the function is now asynchronous and performs IO.

Re: Escape from Callback Hell

#29

Earlier quoted context omitted.

A function that doesn't do IO and a function that does IO sound like totally different functions to me. Why aren't you writing a new function?

doing/not doing IO may be an implementation detail for a function. For example, say you have a function isPrime(x) that you implement using some primality test, with no IO. At some point in the future, you may notice that computing the primality test takes a long time, so instead you decide to submit the number to the server which will then return the answer. The function itself remains the same, it takes in a number…

The function isn't the same, it now how side effects.

Re: Escape from Callback Hell

#30

Earlier quoted context omitted.

A function that doesn't do IO and a function that does IO sound like totally different functions to me. Why aren't you writing a new function?

That isnt the point, its that you have some nice code that does |var x = someBigFunction()| and at some point in the programs life, something inside someBigFunction turns async, you have a whole restructuring to do.

This is just not something that happens in real life. You know what functions are going to be async up-front, and likely make them async even if you don't know, just in case. Since all IO in js is async by default, having a code that does a simple calculation and introducing IO into it is actually a very big change that warrants the refactoring you'll be required to do.
Post reply on HN