Live data from Hacker News

Callbacks as our Generation's Goto Statement

tirania.org

81–90 of 287 posts

Re: Callbacks as our Generation's Goto Statement

#81

Earlier quoted context omitted.

By the way, how do F#'s async workflow compare to ClojureScript? Are they equally powerful?

In F# workflows are just a syntactic sugar for monads, much like Haskell 'do' notation. You can get continuation monad (workflow) in F# easily. I don't know what ClojureScript uses, but it doesn't seem very likely that it has more powerful mechanism :)

Clojure/ClojureScript now has core.async, which is a Go-style implementation of CSP with coroutines and channels.

Like C#, core.async uses a lexical compiler transform to produce a finite state machine for the co-routine. Unlike C#, Clojure can achieve this with a user-level macro, instead of a compiler change. Both C# and core.async differ from Go, in that Go's coroutines have dynamic extend, by virtue of being heap-allocated stacks with a custom scheduler. In practice, this has a minor impact on higher-order usage of co-routines, but is a smaller problem than you'd think, it's generally advisable to minimize higher order usage of side effects.

Both C# and Go's approaches can be implemented as Monads, yes. However, Monads are a significantly more abstract thing than either CSP or C#-style Tasks. The do-notation is barely concealed continuation-passing style, which is generally less pleasant to work with than traditional imperative constructs for side effects such as send & receive. "More powerful" isn't a really useful measurement for practical use.

Re: Callbacks as our Generation's Goto Statement

#82
ES6 generators will be the solution for callback hell in node.js. Node 0.11 already has generators support hidden behind a flag (--harmony-generators) and eventually it will be enabled by default. Generators + libraries like this

https://github.com/jmar777/suspend

will make node.js code more readable.

Re: Callbacks as our Generation's Goto Statement

#83
post #64

Earlier quoted context omitted.

for player in players get_name_for = (player) -> ask "what's your name?", (response) -> if is_valid_name response player.name = response else get_name_for player get_name_for player

This will ask two players simultaneously. My example waits for each player to provide a valid name in turn.

ok, sure, but it's still fixable without having to use await. you'd have to forego the for loop and make that flow control part of the callback cycle.

was your point that it couldn't be done with callbacks? or couldn't be done easily? or not easily alongside traditional flow control like for loops?

I agree, await and async in C# are very nice, I just took your post as a challenge.

  get_player_name = (player, next) ->
    ask "what's your name?", (response) ->
        if is_valid_name response
             player.name = response
             next!
    else get_player_name player, next

  get_player_names = ([player,...players]) ->
    get_player_name player, ->
    	if players.length > 0
            get_player_names players

  get_player_names players

Re: Callbacks as our Generation's Goto Statement

#84

I don't understand what the big deal is. Callbacks are OK. They're less cumbersome if the language you're using has smaller function definitions. Callbacks 'get crazy' when you've got more than one I think, and thankfully someone smart has made a library you can use to manage them! https://github.com/caolan/async Saying that, I don't mind the way things look with the whole await/async stuff in C# and etc. However I d…

How do you do this with callbacks? foreach (var player in players) { while (true) { var name = await Ask("What's your name"); if (IsValidName(name)) { player.name = name; break; } } } Assuming `Ask` is an asynchronous operation and must not block the UI thread. Note that second player is only asked after the first player has given a valid name. (And the code structure reflects that :-) My point is of course it's doab…

I'd do that with the aforementioned `async` library, specifically `async.eachSeries`:

    async.eachSeries players, ask, ->
       # Well that was easy enough...
       printRoster(players)

Re: Callbacks as our Generation's Goto Statement

#86
post #74

Does Await convert those async calls back into synchronous calls, or what does it do? Because that would be kind of defeating the purpose of doing things asynchronously? And you don't have to nest all those callbacks and write them inline. Rearrange your code a bit.

No, it rewrites the method code into a state machine[1].

See Async/Await FAQ[2].

[1]: http://stackoverflow.com/a/4047607/458193 [2]: http://blogs.msdn.com/b/pfxteam/archive/2012/04/12/async-awa...

Re: Callbacks as our Generation's Goto Statement

#87
JS gives you the tools to cope..

  function sequence(fns){
   var fn = fns.pop(); 
   while(fns.length) fn = fns.pop().bind(this, fn); 
   fn();
  }

  sequence([
    function(k) { funcy(1, k) },
    function(k) { funcy(2, k)  },
    function(k) { funcy(3, console.log)  }
  ]);

  function funcy(v, cb){
	console.log(v);	cb(v);
  }

  // ==> 1 2 3 3

Re: Callbacks as our Generation's Goto Statement

#88
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 state through the parameter rather than implicitly sharing state through lexical scoping. It seems more accurate to label the problem of nesting lambdas to the point of ambiguity as "Lambda Abuse" or "Lexical Scoping Abuse" rather than "Callback Hell".

Re: Callbacks as our Generation's Goto Statement

#89
post #83

Earlier quoted context omitted.

This will ask two players simultaneously. My example waits for each player to provide a valid name in turn.

ok, sure, but it's still fixable without having to use await. you'd have to forego the for loop and make that flow control part of the callback cycle. was your point that it couldn't be done with callbacks? or couldn't be done easily? or not easily alongside traditional flow control like for loops? I agree, await and async in C# are very nice, I just took your post as a challenge. get_player_name = (player, next) ->…

Exactly, this was my point.

It took me about as long as I typed this code to write it.

Of course it is doable with callbacks, but I know I'm not smart enough to do it in a comment field on HN.

Re: Callbacks as our Generation's Goto Statement

#90

I don't understand what the big deal is. Callbacks are OK. They're less cumbersome if the language you're using has smaller function definitions. Callbacks 'get crazy' when you've got more than one I think, and thankfully someone smart has made a library you can use to manage them! https://github.com/caolan/async Saying that, I don't mind the way things look with the whole await/async stuff in C# and etc. However I d…

How do you do this with callbacks? foreach (var player in players) { while (true) { var name = await Ask("What's your name"); if (IsValidName(name)) { player.name = name; break; } } } Assuming `Ask` is an asynchronous operation and must not block the UI thread. Note that second player is only asked after the first player has given a valid name. (And the code structure reflects that :-) My point is of course it's doab…

Coroutines (or generators) are a really nice sugar for callbacks. This looks a lot like ES6's yield, just s/await/yield/.

But to answer your question, since these can't be done in parallel, you'd have to keep track of which player you're asking:

    var playersAsked = 0;
    var askNextPlayerHisName = function(done){
        if (playersAsked === players.length) done();

        Ask("What's your name?", function(name){
            if (IsValidName(name)){
                players[playersAsked].name = name;
                playersAsked++;
            }
            askNextPlayerHisName(done);   
        });
    };
    askNextPlayerHisName(function(){/*...*/});
Post reply on HN