Hacker News new | comments | show | ask | jobs | submit login

Callbacks are different than gotos in that they are aren't even remotely close to gotos.

With a callback, you can get into 'callback hell,' however the root cause of that is that you probably don't understand the nuances of properly architecting a solution that involves the power of first-class functions.

JavaScript is nice because the scoping of the callback is easily controllable through your invocation method, and if you've created a good object model then it's relatively easy to maintain an understandable state.

When you explicitly define callbacks like in the examples, you're tightly coupling the response handlers to their requests, which is a relatively poor implementation and will bite you in the ass later on.




Callbacks are different than gotos in that they are aren't even remotely close to gotos.

The analogy is that callbacks create non-linear control flow. Using a monadic syntax like in Roy, we can easily have callbacks without having them look non-linear:

    let deferred = {
      return: \x ->
        let d = $.Deferred ()
        d.resolve x
        d.promise ()
      bind: \x f -> x.pipe f
    }

    let v = do deferred
      hello <- $.ajax 'examples/helloworld.roy'
      alias <- $.ajax 'examples/alias.roy'
      return (hello ++ alias)

    v.done console.log
Which compiles into continuation passing:

    var deferred = {
        "return": function(x) {
            var d = $.Deferred();
            d.resolve(x);
            return d.promise();
        },
        "bind": function(x, f) {
            return x.pipe(f);
        }
    };
    var v = (function(){
        var __monad__ = deferred;
        return __monad__.bind($.ajax('examples/helloworld.roy'), function(hello) {
            return __monad__.bind($.ajax('examples/alias.roy'), function(alias) {
                return __monad__.return((hello + alias));
            });
        });
    })();
    v.done(console.log);
Anyway, continuations (with call/cc) are definitely a controlled form of goto. Take a look at an example from Paul Graham:

http://lib.store.yahoo.net/lib/paulgraham/cint.lisp

    ((call/cc
      (lambda (goto)
        (letrec ((start
                  (lambda ()
                    (print "start")
                    (goto next)))
                 (froz
                  (lambda ()
                    (print "froz")
                    (goto last)))
                 (next
                  (lambda ()
                    (print "next")
                    (goto froz)))
                 (last
                  (lambda ()
                    (print "last")
                    (+ 3 4))))
          start))))


All of structured programming consists of various controlled forms of goto.


Yesterday, I found an email from Jon Callas where he was giving advice on where SAML falls in the Chomsky hierarchy of languages:

"If it has backwards gotos in any form, it's Turing-complete. Loops, recursion, etc. are backwards gotos. If-then-else is a forward goto."

I hadn't ever thought of things that way, but I thought it was interesting.


Once you've worked in assembly language, you realize everything is just another form of jmp.


That's the point of the article, though: callbacks don't offer enough structure to effectively reason about.


> Callbacks are different than gotos in that they are aren't even remotely close to gotos.

Well, continuations are the functional equivalent of GOTOs, and callbacks and continuations are closely related, so I don't know how you can make that statement.

Even if you want to argue that they avoid some of the pitfalls of GOTOs (which I'd still contest), you still can't say that they're "not even remotely close to gotos".


Along with a trampoline, callbacks can be used to implement continuation passing style (CPS), which is more or less a fully generalized goto - not just static goto, but computed goto. CPS is sometimes called "goto with parameters".


"When you explicitly define callbacks like in the examples, you're tightly coupling the response handlers to their requests, which is a relatively poor implementation and will bite you in the ass later on."

I agree, if anything this is an argument about notification vs delegation. Callbacks should be used when you need to delegate a feature, like when an array object needs to call outside its scope to ask for a sorting function. Notifications should be used when the calling object doesn't care who handles the information, like in the case of an asynchronous load, and in a proper notification environment you wouldn't have the spagetti code this blog is illustrating.




Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | DMCA | Apply to YC | Contact

Search: