Loading ...
Sorry, an error occurred while loading the content.

Re: [jslint] Circular Function Definitions

Expand Messages
  • Felix E. Klee
    ... No, that was correct. In the example code, I *was* using a boolean. Only in the real code, things are more complex: Based on what the XHR returns some
    Message 1 of 17 , Jan 4, 2011
    • 0 Attachment
      On Tue, Jan 4, 2011 at 7:53 AM, Erik Eckhardt <erik@...> wrote:
      > I thought you were using a Boolean to indicate whether to make the
      > return call to f.

      No, that was correct. In the example code, I *was* using a boolean. Only
      in the real code, things are more complex:

      Based on what the XHR returns some calculations are performed, and - if
      needed - another XHR is made.

      > The point I was trying to get across is that you don't need the
      > circularity.

      What's bad about the circularity?

      > xhr(params, function() {callback(); f();}); // circular call back to f

      That would again be an infinite loop. The body of the anonymous function
      would need to be at least slightly more complex. I don't think this is
      increases readability.
    • Erik Eckhardt
      If your example isn t the full story, please post an example of the full story! One thing that s wrong with the circularity is the cross-dependence as JSLint
      Message 2 of 17 , Jan 4, 2011
      • 0 Attachment
        If your example isn't the full story, please post an example of the full
        story!

        One thing that's wrong with the circularity is the cross-dependence as
        JSLint is showing you. It's not a huge deal, but an annoying one, perhaps.

        In any case I thought you might find it useful to use some of the techniques
        I mentioned, where if a function determines that an additional step is
        needed, it manages it within the function rather than making the callback
        function have a hard coded reference back. The scheme you're using now seems
        to make sense but as your application grows you may find that it becomes
        unworkable. For example, what if you eventually have two functions that may
        or may not need to be called after an xhr? Are you going to pass two
        booleans? Or God forbid, a code indicating which functions to run? If from
        the start you simply passed around single callback functions (which
        themselves could be a string of functions) this problem would be solved.

        function myxhr(url, params, callback) {
        ___//do stuff;
        doXhr(function() {myxhrreturn(xmlhttp, callback):});
        }

        function myxhrreturn(xmlhttp, callback) {
        ___//process xmlhttp object into a result
        ___callback(result);
        }

        function getsomething() {
        ___myxhr('http://example.com', 'a=1', function(result) {
        ______if (result.blah === 'gorp') {
        _________dosomething;
        ______} else {
        _________dosomethingelse();
        ______}
        ___}
        }

        Now your getsomething function controls everything and all your xmlhttp
        requests can be handled the same way without having to make a hardcoded
        call. If you want the logic in the myxhrreturn function, you can put it
        there, but it's not required. Here's another way to do it:

        function getsomething() {
        var cb;
        if (somecondition) {
        ______cb = function(result) {dosomething(result)};
        ___} else {
        ______cb = function(result) {dosomethingelse(result);};
        ___}
        ___myxhr('http://example.com', 'a=1', cb}
        }

        See how versatile this is? You only need a single callback, no extra Boolean
        parameter is needed to indicate whether to call a hard-coded function name.
        Any time you want more stuff to happen, you can load it into the passed
        callback function somehow.

        Erik

        On Tue, Jan 4, 2011 at 1:47 AM, Felix E. Klee <felix.klee@...> wrote:

        >
        >
        > On Tue, Jan 4, 2011 at 7:53 AM, Erik Eckhardt <erik@...<erik%40eckhardts.com>>
        > wrote:
        > > I thought you were using a Boolean to indicate whether to make the
        > > return call to f.
        >
        > No, that was correct. In the example code, I *was* using a boolean. Only
        > in the real code, things are more complex:
        >
        > Based on what the XHR returns some calculations are performed, and - if
        > needed - another XHR is made.
        >
        >
        > > The point I was trying to get across is that you don't need the
        > > circularity.
        >
        > What's bad about the circularity?
        >
        >
        > > xhr(params, function() {callback(); f();}); // circular call back to f
        >
        > That would again be an infinite loop. The body of the anonymous function
        > would need to be at least slightly more complex. I don't think this is
        > increases readability.
        >
        >


        [Non-text portions of this message have been removed]
      • Felix E. Klee
        On Tue, Jan 4, 2011 at 7:35 PM, Erik Eckhardt ... There may be a misunderstanding. Thus, for your pleasure, below a more real-life
        Message 3 of 17 , Jan 5, 2011
        • 0 Attachment
          On Tue, Jan 4, 2011 at 7:35 PM, Erik Eckhardt <erik@...>
          wrote:
          > no extra Boolean parameter is needed to indicate whether to call a
          > hard-coded function name.

          There may be a misunderstanding.

          Thus, for your pleasure, below a more real-life example. Asides from
          being more verbose, the only difference to my original example is the
          addition of the parameter "liveCommentary". Together with the flag
          "matchIsStillRunning" (formerly: "moreToDo") it forms the data returned
          from the server.

          var sendToServer; // defined elsewhere

          function onCommentaryReceived(commentary, matchIsStillRunning) {
          // write live commentary: ...
          if (matchIsStillRunning) {
          requestCommentary();
          }
          }

          function requestCommentary() {
          sendToServer('Berlin:Munich', onCommentaryReceived);
          }

          Naturally, one could rewrite this:

          var sendToServer; // defined elsewhere

          function requestCommentary() {
          sendToServer('Berlin:Munich',
          function (commentary, matchIsStillRunning) {
          // write live commentary: ...
          if (matchIsStillRunning) {
          requestCommentary();
          }
          });
          }

          The second form avoids the circular function definition, but is it more
          readable?
        • Jordan
          I think the confusion here is that you shouldn t be using the circular function pattern you are using. In addition, you are using function declarations
          Message 4 of 17 , Jan 5, 2011
          • 0 Attachment
            I think the confusion here is that you shouldn't be using the "circular function" pattern you are using. In addition, you are using function declarations rather than assigning a function statement to a variable.

            What you want to do, it seems, is immediately run requestCommentary after a matchIsStillRunning response comes back from the server.

            What I can think of off the top of my head is:

            var onCommentaryReceived = function (commentary, matchIsStillRunning) {
            // write live commentary: ...
            if (matchIsStillRunning) {
            sendToServer('Berlin:Munich', onCommentaryReceived);
            }
            },
            requestCommentary = function () {
            return onCommentaryReceived(null, true);
            };

            Alternatively, and with less refactoring:
            var onCommentaryReceived, requestCommentary;
            onCommentaryReceived = function (commentary, matchIsStillRunning) {
            // write live commentary: ...
            if (matchIsStillRunning) {
            requestCommentary();
            }
            };
            requestCommentary = function () {
            sendToServer('Berlin:Munich', onCommentaryReceived);
            };

            --- In jslint_com@yahoogroups.com, "Felix E. Klee" <felix.klee@...> wrote:
            >
            > On Tue, Jan 4, 2011 at 7:35 PM, Erik Eckhardt <erik@...>
            > wrote:
            > > no extra Boolean parameter is needed to indicate whether to call a
            > > hard-coded function name.
            >
            > There may be a misunderstanding.
            >
            > Thus, for your pleasure, below a more real-life example. Asides from
            > being more verbose, the only difference to my original example is the
            > addition of the parameter "liveCommentary". Together with the flag
            > "matchIsStillRunning" (formerly: "moreToDo") it forms the data returned
            > from the server.
            >
            > var sendToServer; // defined elsewhere
            >
            > function onCommentaryReceived(commentary, matchIsStillRunning) {
            > // write live commentary: ...
            > if (matchIsStillRunning) {
            > requestCommentary();
            > }
            > }
            >
            > function requestCommentary() {
            > sendToServer('Berlin:Munich', onCommentaryReceived);
            > }
            >
            > Naturally, one could rewrite this:
            >
            > var sendToServer; // defined elsewhere
            >
            > function requestCommentary() {
            > sendToServer('Berlin:Munich',
            > function (commentary, matchIsStillRunning) {
            > // write live commentary: ...
            > if (matchIsStillRunning) {
            > requestCommentary();
            > }
            > });
            > }
            >
            > The second form avoids the circular function definition, but is it more
            > readable?
            >
          • Felix E. Klee
            ... The question is: Why? Is that considered bad practice? If so, a reference please. ... See my original post. There I mentioned that I would like to enforce
            Message 5 of 17 , Jan 6, 2011
            • 0 Attachment
              On Thu, Jan 6, 2011 at 6:27 AM, Jordan <ljharb@...> wrote:
              > I think the confusion here is that you shouldn't be using the
              > "circular function" pattern you are using.

              The question is: Why? Is that considered bad practice? If so, a
              reference please.

              > In addition, you are using function declarations rather than assigning
              > a function statement to a variable.

              See my original post. There I mentioned that I would like to enforce
              that convention for the whole project using JSLint. Only I wonder why
              there is no such option.

              > What I can think of off the top of my head is:
              >
              > [...]
              > requestCommentary = function () {
              > return onCommentaryReceived(null, true);
              > };

              That would work, but it's confusing to read. At least the function name
              "onCommentaryReceived" should be changed.

              > Alternatively, and with less refactoring:

              See my original post. It's there already.
            • Felix E. Klee
              On Fri, Dec 31, 2010 at 6:33 PM, Felix E. Klee ... Just figured that this is akin to: http://en.wikipedia.org/wiki/Mutual_recursion And I
              Message 6 of 17 , Jan 8, 2011
              • 0 Attachment
                On Fri, Dec 31, 2010 at 6:33 PM, Felix E. Klee <felix.klee@...>
                wrote:
                > If I write code such as the following

                Just figured that this is akin to:

                http://en.wikipedia.org/wiki/Mutual_recursion

                And I checked: The latest version of JSLint, 2011-01-06, still
                complains about an undefined function.
              • Douglas Crockford
                ... ` var sendToServer; ` ` function f() { ` sendToServer( xyz , function (moreToDo) { ` // do something ... ` if (moreToDo) { `
                Message 7 of 17 , Jan 8, 2011
                • 0 Attachment
                  --- In jslint_com@yahoogroups.com, "Felix E. Klee" <felix.klee@...> wrote:
                  >
                  > If I write code such as the following, then JSLint complains that "f" is
                  > not defined.
                  >
                  > var sendToServer;
                  >
                  > function callback(moreToDo) {
                  > // do something ...
                  > if (moreToDo) {
                  > f();
                  > }
                  > }
                  >
                  > function f() {
                  > sendToServer('xyz', callback);
                  > }
                  >
                  > What's the most elegant solution to get rid of the error message?


                  ` var sendToServer;
                  `
                  ` function f() {
                  ` sendToServer('xyz', function (moreToDo) {
                  ` // do something ...
                  ` if (moreToDo) {
                  ` f();
                  ` }
                  ` });
                  ` }
                • Felix E. Klee
                  On Sat, Jan 8, 2011 at 4:05 PM, Douglas Crockford ... Thanks for the suggestion! I guess I ll take this approach and put the lengthy do something into a
                  Message 8 of 17 , Jan 8, 2011
                  • 0 Attachment
                    On Sat, Jan 8, 2011 at 4:05 PM, Douglas Crockford
                    <douglas@...> wrote:
                    > ` var sendToServer;
                    > `
                    > ` function f() {
                    > ` sendToServer('xyz', function (moreToDo) {
                    > ` // do something ...
                    > ` if (moreToDo) {
                    > ` f();
                    > ` }
                    > ` });
                    > ` }

                    Thanks for the suggestion! I guess I'll take this approach and put the
                    lengthy "do something" into a separate function.

                    Just thinking about it: I assume that having JSLint to *not* report an
                    error on circular function definitions is non-trivial. That is, if one
                    still wants to be warned about cases were an undefined function would be
                    called, such as:

                    function f() {
                    g();
                    }

                    f();

                    function g() {
                    // do something
                    }
                  Your message has been successfully submitted and would be delivered to recipients shortly.