Live data from Hacker News

Callbacks as our Generation's Goto Statement

tirania.org

141–150 of 287 posts

Re: Callbacks as our Generation's Goto Statement

#141
(C/OS developer spiel)

I'm sick of these app developers assuming that using "goto" is bad practice. The fact is that "goto" is used plenty in great production code you're probably running right now.[1] I'd like to know a cleaner way to abort a function into its cleanup phase when a function call returns an error. And "goto" statements are extremely simple to handle for even the most naive of compilers.

[1] https://www.kernel.org/doc/Documentation/CodingStyle (see chapter 7)

Re: Callbacks as our Generation's Goto Statement

#142
shenanigans. Pyramids (at least in js) can be easily avoided by simply naming your functions. Treating them like the first class objects they are. Naming the function means you are no longer going to an arbitrary code block, but instead going to a concept whose name, doc string, and (through hoisting) position on the page illuminate its purpose.

Callbacks aren't bad. Pyramids are bad. Stop writing pyramids.

Nodejs also establishes a nice api for callback functions-- in particular, callbacks are defined with an `error` and a `data` argument. You handle the error if it is non-null, otherwise execute `data`.

If you want to avoid callbacks, Node also provides event emitters, and streams. Streams in particular provide a nice api for dealing with event based programming.

Re: Callbacks as our Generation's Goto Statement

#143
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#)?

this use case is inherently more complicated than any of the control flow structures you mention here. You are introducing a new closure, and you don't know when the function is going to be executed.

Re: Callbacks as our Generation's Goto Statement

#144
post #30

Earlier quoted context omitted.

This sounds sweet. In my book, C# designers have a history of striking a good balance between simplicity and flexibility. This however always leaves me eager to look at Haskell/ClojureScript/other languages where concepts that C# borrowed and simplified are taken to the full (such as monads, iterators, CSP, etc).

The C# designers outdid themselves this time. I'm surprised they managed to made this feature so simple and succinct, especially for an "enterprise" language. Those two little words (async/await) seem like something I would expect from a language like Python or Ruby. Had it been Java, it would be called AsynchronousBureaucraticProccessDispatcherFactoryFactoryFactory.

Aw come on. Have you ever programmed in Java? Anybody who has written any java code knows that class name is wrong.

AsynchronousBureaucraticProccessDispatcherFactoryFactoryFactoryInterfaceProvider

There I fixed it for you. And of course you have to specify the provider in the META-INF/async file.

Re: Callbacks as our Generation's Goto Statement

#145

Anonymous Callbacks != Callbacks Callbacks have been around forever in C using named functions, and are not specific to either the current generation of programming languages or programmers. One can still use a named function instead of a locally constructed lambda to represent a callback in a high level languages. The primary difference is that when declaring named functions non-locally, one must explicitly share st…

Not totally, the problem being described as "Callback Hell" is in my experience: non-locality of code. Things that relate to one another should be spatially together for a programmer to write, read, understand- and NOT split into success and error conditions around the axis of final callback.

Even with named functions, this is the problem- right? You pass in a named callback and you have to find that function later when you're debugging to figure out what's going on. Locality of code means no breaking context to find something not already on screen and therefore easier programming.

Re: Callbacks as our Generation's Goto Statement

#146
post #133

I have a basic technical question. I work in C for embedded systems, so I'm a bit "behind the times." How is "await" any different from a regular blocking system call? A regular system call does exactly what is being described: The system call happens, and then when it is finished, execution resumes where it left off. (Yes, this makes the thread block... which is why you have multiple threads. I think the answer will…

I'm not a beliver, so I may be missing something important...

As far as I can see, await makes it possible to do things like:

- UI Thread starts Thread X to do something slow; - Thread X is processing, in the meantime the user clicks on something that requires X's result; - Only now the UI thread stops, waiting for X.

Your program stay responsive, unless it's completely not able to do so.

As I said, I still don't think it's a so important feature. It is quite rare that one needs such kind of coordination in UI programs, and there are better mechanisms for no-interactive software (that optimize for throughput, not responsiveness)... As a second thought, it may be very relevant for games, I don't know.

I also don't get why the node.js people consider it so important to have concurrence at a web server. For me, it only makes sense for sites that have less concurrent requests than server cores, AKA: nobody.

Re: Callbacks as our Generation's Goto Statement

#147
I generally agree that there are better ways to handle asynchronous control flow than callbacks, but I think this is exaggerated. As in most posts like this, the callback soup examples are difficult to follow primarily because they are horribly written, not because of callbacks.

As long as you write decent code, the main impediment to asynchronous programming is reasoning asynchronously, not syntax. If you require complex asynchronous logic and don't use an appropriate algorithm, you'll end up in the muck whether you use callbacks or await.

Taking go as an example: while I agree that the go statement is more elegant than a callback approach, I see it as quite a minor win compared to channels. The go statement is convenient syntax, but channels are what make concurrency in go feel so robust, and it's a pattern than can be applied just as well in a language that uses callbacks.

Re: Callbacks as our Generation's Goto Statement

#148
post #27

The ease with which callbacks can be created leads people to create them carelessly and excessively. While I like what the article has to say, there are ways to write callback heavy code that do not get ugly so fast. Looking at the iOS nested block example from Marco Arment -- the first step is to not do everything inline. Then the code suddenly becomes clear and the argument becomes one of syntax sugar. Comparing ca…

First: code that performs simple sequential steps should look simple. With callbacks, it always ends up looking complicated. Second: refactorability in callback oriented code is a lot worse than linear code. Even refactoring code with a single callback can be annoying. Async code with callbacks that looks and feels like imperative synchronous code is an enormous gain.

Code that performs simple sequential steps should be synchronous.

Keep the asynchronous complications at the code that perform non-sequential steps. And yes, I'm fully aware that some libraries (Javascript's one, the guilty are always the same few) force you to use asynchronous calls. That's a flaw of the library.

Re: Callbacks as our Generation's Goto Statement

#149

Earlier quoted context omitted.

Same problem like with the sibling post: this will ask two players simultaneously. My example waits for each player to provide a valid name in turn.

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.

Re: Callbacks as our Generation's Goto Statement

#150
post #95

Earlier quoted context omitted.

Very true. :) The genius about them, however, is that with all those, we discovered that you could get rid of "goto" afterwards. Which was kind of amazing. "Await", on the other hand, doesn't remove the need for callbacks -- it just makes it much easier to use them in a lot of common use cases, in a much clearer way. But there are still plenty of valid/necessary uses for callbacks that can't be handled by "await".

On the contrary, there are still perfectly good uses for goto. The two I can name right off the top of my head are stack-like error unwinding in C (which comes with an endorsement from CERT recommending its use) and computed goto dispatch tables in threaded interpreters. Still, you're right that structured control flow statements have obsoleted goto for all but the tiniest edge cases, and so too do I look forward to…

Most definitely. I wish people actually read http://www.u.arizona.edu/~rubinson/copyright_violations/Go_T... to understand why Dijkstra's argument doesn't apply to the cases you describe.
Post reply on HN