Live data from Hacker News

Callbacks as our Generation's Goto Statement

tirania.org

251–260 of 287 posts

Re: Callbacks as our Generation's Goto Statement

#251
post #53

Earlier quoted context omitted.

> the visual structure of callback-oriented programs doesn't reflect the order of execution. One of my bosses made this assertion about Object Oriented code that followed the Law of Demeter and other OO best practices. I don't think he's entirely the best OO person, or entirely on the right track. However, I would venture to say that all programming paradigms hit a point where visualizing the flow of control gets exh…

Callback-oriented code is different. With by-the-book OOP code you're still executing one line at a time. You might be teleporting in space, which has its own problems, but your code still reflects the order of execution. With callback-oriented code you're teleporting in space and time. They can both make it hard to trace the path of execution. At least with OOP code you have a sensible stack trace, though. ;)

True about the stack trace, but teleporting around in space is still the same kind of difficulty. You're taking a whole and scattering it around.

Re: Callbacks as our Generation's Goto Statement

#252

The problem is simply that those languages are not Lisp. Once good patterns of use of GOTO were found, it was natural to critisize random uses, and to wrap good uses in a lisp macro. Or in a new while or for "instruction". But then the next construct is discovered, and its bad uses considered harmful, and its good uses need to be wrapped. In lisp, mere programmers will just write the next macro to abstract away this…

Ah, but the real problem is not that these languages aren't Lisp, but that they aren't Scheme. People are being forced to write continuation-passing-style code by hand, which anyone would agree is painful. To allow user-level code to abstract away the need to write CPS, you need call/cc (or something like it).

"The infinite improbability drive is a wonderful new method of crossing interstellar distances in a mere nothingth of a second, without all that tedious mucking about in hyperspace."

Re: Callbacks as our Generation's Goto Statement

#253
post #134

As someone who only recently switched to Node.js from PHP I personally haven't had any difficulty switching over to the callback frame of mind, and I haven't experienced the "callback hell" so many people complain about. At first I was hesitant to start with Node because I saw blog posts by people bemoaning the spaghetti callback code that they ended up with. But I haven't experienced any of that, although I am a rel…

I often write synchronous methods that include control flow that nests three deep (say try/finally, if/then/else, and a for loop). Often it's easier to read this code than it would be if everything were split out into separate named methods. Why would the same not be true of asynchronous methods, assuming that the technology was there to enable it (as it is in C#)?

> Often it's easier to read this code than it would be if everything were split out into separate named methods.

This might actually be a shortcoming of our code organization/reading tools.

Re: Callbacks as our Generation's Goto Statement

#254
post #229
post #221

Earlier quoted context omitted.

Something like go's defer makes most uses of goto (failure handling) unnecessary. However, there is still the "code a state machine" use case for goto.

Which we are trying to eliminate with tail-call-optimized mutually recursive functions.

Which are semantically less clear than goto, when you are working with something that is semantically a state machine.

Re: Callbacks as our Generation's Goto Statement

#255

As someone who only recently switched to Node.js from PHP I personally haven't had any difficulty switching over to the callback frame of mind, and I haven't experienced the "callback hell" so many people complain about. At first I was hesitant to start with Node because I saw blog posts by people bemoaning the spaghetti callback code that they ended up with. But I haven't experienced any of that, although I am a rel…

I'm tired to the utmost degree of all these posts about people (supposedly) coming from PHP/C#/Ruby/Python background and seeing "absolutely no problems" with JS syntax, object model and programming paradigms. There are problems. They are objectively there. If you don't see them, you have to check your critical thinking skills, rather than imply that everyone outside of elite JS circles are simply too ignorant to understand its awesomeness.

The simplest example of callback hell is trying to analyze workflow of some chunk of code in a debugger. If the code is linear, you place a breakpoint at the beginning of the method you're interested in and go through the code one line at a time. If there are nested statement of method calls, the debugger happily redirect you to them without fail.

With extensive use of callbacks, this becomes impossible. Since callbacks are merely registered in the original method, you need to place a breakpoint at the beginning of every callback function you might encounter in advance. Named callbacks actually make this worse by physically separating the place where a function is registered from its body. Did I mention that you're loosing ability to do any kinds of static reasoning, since callbacks are inherently a runtime concept? And the fact that you loose ability to look at the stack trace to "reverse engineer" why something was called?

Which reminds me of something. Have you ever seen code that reads a global variable, and you have no clue where the value came from? Callbacks create the exact same problem, except they aren't just data, they are code, so the problem can be nested multiple times.

Re: Callbacks as our Generation's Goto Statement

#256
post #229

Earlier quoted context omitted.

Which we are trying to eliminate with tail-call-optimized mutually recursive functions.

Which are semantically less clear than goto, when you are working with something that is semantically a state machine.

Actually, I think that mutually-recursive functions are more semantically clear than goto for a state machine, though using explicit state objects is even more clear than either (though probably less efficient.)

Re: Callbacks as our Generation's Goto Statement

#257

"Await" is fantastic, and having using it for JavaScript (via TameJS and then IcedCoffeeScript), it makes things a lot easier and clearer. That being said, I don't think the comparison between callbacks and goto is valid. "Goto" allows you to create horrible spaghetti-code programs, and getting rid of it forces you to structure your programs better. "Await", fundamentally, isn't really anything more than syntactic su…

There's nothing inherently harmful about goto either, and people who think that just having it around is death, seriously don't understand the machines they're programming, and how we implement these magical control structures they love so much. (hint: we use goto)

I don't feel any respect for the article because it's written on the premise that goto is bad, and that it is anything like a callback.

Callbacks have been, and will continue to be an incredibly useful way to handle events.

Re: Callbacks as our Generation's Goto Statement

#258

Earlier quoted context omitted.

If you're doing everything sequentially anyway, why bother with the awaiting part? As far as I can see your example would be functionally unchanged if you wrote the same code except without the await keyword.

Because it doesn't block the thread. The idea is that this code is executed inside of a thread that, if it blocks, will cause the application to hang. For example, in a GUI or a server. So, if its a thread driving a GUI, and it's blocked on user input, then the entire application interface will be unresponsive until it receives that input.

Great comment! I missed that.

Re: Callbacks as our Generation's Goto Statement

#259

As someone who only recently switched to Node.js from PHP I personally haven't had any difficulty switching over to the callback frame of mind, and I haven't experienced the "callback hell" so many people complain about. At first I was hesitant to start with Node because I saw blog posts by people bemoaning the spaghetti callback code that they ended up with. But I haven't experienced any of that, although I am a rel…

I'm tired to the utmost degree of all these posts about people (supposedly) coming from PHP/C#/Ruby/Python background and seeing "absolutely no problems" with JS syntax, object model and programming paradigms. There are problems. They are objectively there. If you don't see them, you have to check your critical thinking skills, rather than imply that everyone outside of elite JS circles are simply too ignorant to und…

Well in addition to not having a problem with callback hell I also haven't used a debugger in more than three years, so I guess I'm just weird.

As I said I like to write unit tests with my named callbacks. This allows me to test the callbacks as well as the root level functions that make use of these callbacks to ensure that everything is working perfectly.

When I follow this model it is extremely rare that I ever encounter any issues that would need a debugger, and if a problem does arise somewhere the relevant unit test can quickly expose which callback is having a trouble, and precisely what is wrong.

I'm not saying callbacks are perfect. My goal is just to share my technique for organizing my code in Node which I feel has led to some very well organized, testable, and maintainable code.

Re: Callbacks as our Generation's Goto Statement

#260

At least for java, when your software library exists in the cloud, I don't see how you could avoid using callbacks.

This is possible if the language supports coroutines like python (see twisted's inline callbacks) or my port to Lua for Luvit: https://github.com/kans/luvit-inlineCallbacks.

Personally, I think raw callbacks are the right thing 95% of the time. yield/async/coroutines are needed for branching async logic where otherwise you'd be forced to make a new function for each branch and deal with the spaghetti at the end.

Post reply on HN