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

Re: [jslint] && as flow control

Expand Messages
  • Michael Mikowski
    If you use jslint and have read the good parts, you certainly should be aware of type coercion. Using && and || for flow control doesn t require coercion
    Message 1 of 12 , Mar 12 4:44 PM
    • 0 Attachment
      If you use jslint and have read "the good parts," you certainly should be aware of type coercion. Using && and || for flow control doesn't require coercion but it certainly encourages it. Writing this:

      ary[0] && obj['key'] && bar && alert('guantlet passed');

      gives us 3 type coercions, roughly equivalent to:

      ( ary[0] == true ) && ( obj['key'] == true ) && ( bar == true ) && alert('gauntlet passed');

      As for "(maybe, unless it is autovivified)," how many people need to look that up? Because js does "pretend" keys exist when looking up an array or object value. To wit:

      // false if ary[0] does not exist OR if it does exist and the value is not "truthy"
      ary[0] ....

      // true only if array has element 0
      ary.hasOwnProperty(0) ...

      And before anyone asks, the latest version of firebug (1.5.2) with STRICT warnings doesn't show a thing if you address uninitialized ary[x] where x can be any numerical value (it does catch object keys, however).

      The Good Parts doesn't go into depth about it, but on page 120 when explaining jslint, it states: "An expression statement is expected to be an assignment, a function/method call, or delete. All other expression statements are considered errors." Type coercion errors are discussed on page 121.


      In the end, using expression statements can give you all the terseness of a regular expression without the precision and power. It can be the worst of both worlds. They don't pass our code reviews.




      ________________________________
      From: Stefan Weiss <weiss@...>
      To: jslint_com@yahoogroups.com
      Sent: Fri, March 12, 2010 2:09:38 PM
      Subject: Re: [jslint] && as flow control


      Michael Mikowski wrote:
      > Probably because type coercion is considered sloppy programming in any
      > language. In this case, foo[0] test for "truthiness" which means the
      > value must be /true/, or non-zero, or a non-empty string, or defined
      > (maybe, unless it is autovivified) , or ... and the list goes on.

      There's no Autovivification in JS, maybe you were thinking of Perl.
      Anyway, type coercion can't be the reason for the JSLint error, or this
      construct would pass:

      typeof foo[0] == "undefined" && fop = foo.shift();

      Type coercion can happen with or without this use of '&&' for flow
      control, same as with the more usual if/else. I rather suspect there are
      two other problems with this statement. The first is the assignment: if
      you wrap it in parentheses, JSLint will parse it correctly and issue a
      different warning:

      foo[0] && (fop = foo.shift()) ;

      "Expected an assignment or function call and instead saw an expression."

      Expression statements are valid in ECMAScript, but they aren't part of
      DC's Good Parts. I don't have the book at home, so I can't look up the
      rationale for that right now; maybe someone else can.

      > Can you name all "truthy" or "falsy" conditions off the top of your
      > head? How many on your team can?

      It's impossible to name all truthy values, but the falsy ones should be
      known to every JS developer. There aren't that many: null, undefined, 0,
      false, '', and NaN.

      I agree that it's harder to remember all the different rules for type
      coercion. For example:

      var x = new String("");

      // this prints "true"
      if (x) { console.log( "true"); }

      // and so does this, go figure...
      if (x == false) { console.log( "true"); }

      There are many other confusing examples like this.

      stefan



      [Non-text portions of this message have been removed]
    • Stefan Weiss
      ... And the exact same thing happens if you don t use expression statements: if (ary[0] && obj[ key ] && bar) { alert( guantlet passed ); } Expression
      Message 2 of 12 , Mar 12 6:08 PM
      • 0 Attachment
        Michael Mikowski wrote:
        > Using && and || for flow control doesn't
        > require coercion but it certainly encourages it. Writing this:
        >
        > ary[0] && obj['key'] && bar && alert('guantlet passed');
        >
        > gives us 3 type coercions, roughly equivalent to:
        >
        > ( ary[0] == true ) && ( obj['key'] == true ) && ( bar == true ) &&
        > alert('gauntlet passed');

        And the exact same thing happens if you don't use expression statements:

        if (ary[0] && obj['key'] && bar) {
        alert('guantlet passed');
        }

        Expression statements and type coercion are not directly related; it's
        the "&&" operator which forces boolean context. If you don't want the
        value of "ary[0]" or "bar" or whatever evaluated in boolean context,
        then don't use "&&", or do an explicit comparison with the correct type.

        In many situations, like when the possible contents of "ary" are known,
        or when all falsy values are to be excluded, it's more concise to use
        "&&". Nothing wrong with that, if you know what you're doing - there are
        tens of valid examples in the JSLint source itself.

        > As for "(maybe, unless it is autovivified)," how many people need to
        > look that up? Because js does "pretend" keys exist when looking up an
        > array or object value. To wit:
        >
        > // false if ary[0] does not exist OR if it does exist and the value is
        > not "truthy"
        > ary[0] ....
        >
        > // true only if array has element 0
        > ary.hasOwnProperty(0) ...
        >
        > And before anyone asks, the latest version of firebug (1.5.2) with
        > STRICT warnings doesn't show a thing if you address uninitialized ary[x]
        > where x can be any numerical value (it does catch object keys, however).

        That doesn't prove that ary[0] is autovivified, only that Mozilla
        decided not to issue a strict warning when a nonexistent array index is
        accessed. If there was any autovivification, the property "0" would
        exist after an attempt to read it. This is not the case:

        var ary = [];
        console.log(ary[0]); // "undefined"
        for (var prop in ary) { console.log(prop); } // nothing

        (Aside, I think the "strict" warnings in Firefox are way over the top. I
        don't know any other developer who pays attention to them. Even the
        JSLint script triggers numerous warnings.)

        > The Good Parts doesn't go into depth about it, but on page 120 when
        > explaining jslint, it states: "An expression statement is expected to be
        > an assignment, a function/method call, or delete. All other expression
        > statements are considered errors."

        Thanks for checking.
        I guess the OP was hoping for more of an explanation.

        By the way, I can think of a couple more expression statements that are
        accepted by JSLint: pre/postfix increment and decrement, bit shifting,
        and '"use strict";' (the former two are not part of the Good Parts, and
        there are options to disallow them).

        > In the end, using expression statements can give you all the terseness
        > of a regular expression without the precision and power. It can be the
        > worst of both worlds. They don't pass our code reviews.

        I don't understand the comparison with regular expressions. Anyway, I'm
        not in any way advocating the use of these "flow control" expression
        statements. I happen to like them (but then, I also like Perl), others
        don't, no big deal. They are easy enough to avoid when I'm writing
        JSLint compatible scripts.


        stefan
      • Michael Mikowski
        From: Stefan Weiss To: jslint_com@yahoogroups.com Sent: Fri, March 12, 2010 6:08:23 PM Subject: Re: [jslint] && as flow control ... I think we
        Message 3 of 12 , Mar 12 6:43 PM
        • 0 Attachment
          From: Stefan Weiss <weiss@...>
          To: jslint_com@yahoogroups.com
          Sent: Fri, March 12, 2010 6:08:23 PM
          Subject: Re: [jslint] && as flow control

          > Expression statements and type coercion are not directly related; it's
          > the "&&" operator which forces boolean context. If you don't want the
          > value of "ary[0]" or "bar" or whatever evaluated in boolean context,
          > then don't use "&&", or do an explicit comparison with the correct type.

          I think we agree. This is our example, but written for better precision:

          if ( arg.hasOwnProperty(0) && obj.hasOwnProperty(0) && bar === true ){...}

          > That doesn't prove that ary[0] is autovivified, only that Mozilla
          > decided not to issue a strict warning when a nonexistent array index is
          > accessed. If there was any autovivification, the property "0" would
          > exist after an attempt to read it. This is not the case.

          True, js does not autovivify. But during comparisons it acts like it does.
          So if one is using "if (ary[x])" to test if an element exists, they are
          in for an unpleasant surprise when it comes time to debug.

          I wasn't advocating the idea of using strict warnings either, just illustrating
          that even with the strictest warnings there is no way to tell if an array value
          is uninitialized unless you directly check for it.

          > I don't understand the comparison with regular expressions.

          Don't get me wrong - I love regular expressions and use them all the time.
          They can be very precise and powerful. It is their terseness that scares
          a lot of people, and makes them hard to debug sometimes.
          Flow controls like 'ary[0] && obj['key'] && bar && ...'
          are also terse, but lack precision, so they can be even more difficult to debug.

          > Anyway, I'm
          > not in any way advocating the use of these "flow control" expression
          > statements. I happen to like them (but then, I also like Perl), others
          > don't, no big deal. They are easy enough to avoid when I'm writing
          > JSLint compatible scripts.

          Never say never; everything has its place :) Oh, and I'm a big fan of
          Perl too :)




          ________________________________
          From: Stefan Weiss <weiss@...>
          To: jslint_com@yahoogroups.com
          Sent: Fri, March 12, 2010 6:08:23 PM
          Subject: Re: [jslint] && as flow control


          Michael Mikowski wrote:
          > Using && and || for flow control doesn't
          > require coercion but it certainly encourages it. Writing this:
          >
          > ary[0] && obj['key'] && bar && alert('guantlet passed');
          >
          > gives us 3 type coercions, roughly equivalent to:
          >
          > ( ary[0] == true ) && ( obj['key'] == true ) && ( bar == true ) &&
          > alert('gauntlet passed');

          And the exact same thing happens if you don't use expression statements:

          if (ary[0] && obj['key'] && bar) {
          alert('guantlet passed');
          }

          Expression statements and type coercion are not directly related; it's
          the "&&" operator which forces boolean context. If you don't want the
          value of "ary[0]" or "bar" or whatever evaluated in boolean context,
          then don't use "&&", or do an explicit comparison with the correct type.

          In many situations, like when the possible contents of "ary" are known,
          or when all falsy values are to be excluded, it's more concise to use
          "&&". Nothing wrong with that, if you know what you're doing - there are
          tens of valid examples in the JSLint source itself.

          > As for "(maybe, unless it is autovivified) ," how many people need to
          > look that up? Because js does "pretend" keys exist when looking up an
          > array or object value. To wit:
          >
          > // false if ary[0] does not exist OR if it does exist and the value is
          > not "truthy"
          > ary[0] ....
          >
          > // true only if array has element 0
          > ary.hasOwnProperty( 0) ...
          >
          > And before anyone asks, the latest version of firebug (1.5.2) with
          > STRICT warnings doesn't show a thing if you address uninitialized ary[x]
          > where x can be any numerical value (it does catch object keys, however).

          That doesn't prove that ary[0] is autovivified, only that Mozilla
          decided not to issue a strict warning when a nonexistent array index is
          accessed. If there was any autovivification, the property "0" would
          exist after an attempt to read it. This is not the case:

          var ary = [];
          console.log( ary[0]); // "undefined"
          for (var prop in ary) { console.log( prop); } // nothing

          (Aside, I think the "strict" warnings in Firefox are way over the top. I
          don't know any other developer who pays attention to them. Even the
          JSLint script triggers numerous warnings.)

          > The Good Parts doesn't go into depth about it, but on page 120 when
          > explaining jslint, it states: "An expression statement is expected to be
          > an assignment, a function/method call, or delete. All other expression
          > statements are considered errors."

          Thanks for checking.
          I guess the OP was hoping for more of an explanation.

          By the way, I can think of a couple more expression statements that are
          accepted by JSLint: pre/postfix increment and decrement, bit shifting,
          and '"use strict";' (the former two are not part of the Good Parts, and
          there are options to disallow them).

          > In the end, using expression statements can give you all the terseness
          > of a regular expression without the precision and power. It can be the
          > worst of both worlds. They don't pass our code reviews.

          I don't understand the comparison with regular expressions. Anyway, I'm
          not in any way advocating the use of these "flow control" expression
          statements. I happen to like them (but then, I also like Perl), others
          don't, no big deal. They are easy enough to avoid when I'm writing
          JSLint compatible scripts.

          stefan



          [Non-text portions of this message have been removed]
        • Dave
          Thanks MLorton and SWeiss for the good feedback. The discussion about type coercion was an off the topic disection of my analogy, not a succinct answer to the
          Message 4 of 12 , Mar 17 3:28 PM
          • 0 Attachment
            Thanks MLorton and SWeiss for the good feedback.

            The discussion about type coercion was an off the topic disection of my analogy, not a succinct answer to the '&&' as flow control issue.

            So thanks you two for staying on topic.

            Dave

            --- In jslint_com@yahoogroups.com, "Dave" <david.hampton@...> wrote:
            >
            > Many languages allow a convenience in scripting that allows an && to be used as flow control.
            >
            > var foo = [1,2,3,4];
            >
            > foo[0] && fop = foo.shift(); //assigns the first element of foo to fop, if it exists.
            >
            > Conversely, an || statement can be used for alternate functionality.
            >
            > JavaScript also allows this, but jslint does not. I'm curious as to why.
            >
            > Dave
            >
            > P.S., this may have been answered asked before, but it seems that the search functionality of YAHOO! Groups scrubs the '&' character...
            >
          • Michael Mikowski
            ... Sorry it didn t help you Dave. ________________________________ From: Dave To: jslint_com@yahoogroups.com Sent: Wed, March 17,
            Message 5 of 12 , Mar 17 6:07 PM
            • 0 Attachment
              Type coercion certainly seemed on-topic, as the comment for the following line is wrong precisely because of it:


              > foo[0] && fop = foo.shift(); //assigns the first element of foo to fop, if it exists.

              Sorry it didn't help you Dave.




              ________________________________
              From: Dave <david.hampton@...>
              To: jslint_com@yahoogroups.com
              Sent: Wed, March 17, 2010 3:28:09 PM
              Subject: [jslint] Re: && as flow control


              Thanks MLorton and SWeiss for the good feedback.

              The discussion about type coercion was an off the topic disection of my analogy, not a succinct answer to the '&&' as flow control issue.

              So thanks you two for staying on topic.

              Dave

              --- In jslint_com@yahoogro ups.com, "Dave" <david.hampton@ ...> wrote:
              >
              > Many languages allow a convenience in scripting that allows an && to be used as flow control.
              >
              > var foo = [1,2,3,4];
              >
              > foo[0] && fop = foo.shift(); //assigns the first element of foo to fop, if it exists.
              >
              > Conversely, an || statement can be used for alternate functionality.
              >
              > JavaScript also allows this, but jslint does not. I'm curious as to why.
              >
              > Dave
              >
              > P.S., this may have been answered asked before, but it seems that the search functionality of YAHOO! Groups scrubs the '&' character...
              >




              [Non-text portions of this message have been removed]
            • pauanyu
              I am not Douglas, so I cannot speak for him, but here is my opinion on the matter. I believe the reason JSLint does not accept using && and || for flow control
              Message 6 of 12 , Mar 18 4:45 AM
              • 0 Attachment
                I am not Douglas, so I cannot speak for him, but here is my opinion on the matter.

                I believe the reason JSLint does not accept using && and || for flow control is because they are usually misunderstood and confusing to people who are not experienced with JavaScript.

                I have seen some people who assumed that those two operators return true or false, not the operands. Until you have sufficient knowledge and experience with JavaScript, using those operators for flow control can be very confusing.

                Which brings me to my second point: style. JSLint, in addition to checking for genuine errors, also occasionally enforces style conventions as well, usually with the goal of making your code more readable.

                Compare these two blocks of code:

                (typeof foo === "function") && foo();

                if (typeof foo === "function") {
                foo();
                }

                Although the first is certainly more concise, it is also confusing to people who do not understand how boolean operators work in JavaScript. On the other hand, almost everybody understands how "if" blocks work. As a consequence, the second version is less confusing, though it also consumes more space.

                Personally, I like using the boolean operators for flow control, but I believe the issues above are why JSLint forbids it.

                --- In jslint_com@yahoogroups.com, "Dave" <david.hampton@...> wrote:
                >
                > Many languages allow a convenience in scripting that allows an && to be used as flow control.
                >
                > var foo = [1,2,3,4];
                >
                > foo[0] && fop = foo.shift(); //assigns the first element of foo to fop, if it exists.
                >
                > Conversely, an || statement can be used for alternate functionality.
                >
                > JavaScript also allows this, but jslint does not. I'm curious as to why.
                >
                > Dave
                >
                > P.S., this may have been answered asked before, but it seems that the search functionality of YAHOO! Groups scrubs the '&' character...
                >
              Your message has been successfully submitted and would be delivered to recipients shortly.