What does "!--" do in JavaScript?

JavascriptDecrementPrefix OperatorNot Operator

Javascript Problem Overview


I have this piece of code (taken from this question):

var walk = function(dir, done) {
    var results = [];

    fs.readdir(dir, function(err, list) {
        if (err)
            return done(err);

        var pending = list.length;

        if (!pending) 
            return done(null, results);

        list.forEach(function(file) {
            file = path.resolve(dir, file);
            fs.stat(file, function(err, stat) {
                if (stat && stat.isDirectory()) {
                    walk(file, function(err, res) {
                        results = results.concat(res);

                        if (!--pending)
                            done(null, results);
                    });
                } else {
                    results.push(file);

                    if (!--pending) 
                        done(null, results);
                }
            });
        });
    });
};

I'm trying to follow it, and I think I understand everything except for near the end where it says !--pending. In this context, what does that command do?

Edit: I appreciate all the further comments, but the question has been answered many times. Thanks anyway!

Javascript Solutions


Solution 1 - Javascript

! inverts a value, and gives you the opposite boolean:

!true == false
!false == true
!1 == false
!0 == true

--[value] subtracts one (1) from a number, and then returns that number to be worked with:

var a = 1, b = 2;
--a == 0
--b == 1

So, !--pending subtracts one from pending, and then returns the opposite of its truthy/falsy value (whether or not it's 0).

pending = 2; !--pending == false 
pending = 1; !--pending == true
pending = 0; !--pending == false

And yes, follow the ProTip. This may be a common idiom in other programming languages, but for most declarative JavaScript programming this looks quite alien.

Solution 2 - Javascript

That's not a special operator, it's 2 standard operators one after the other:

  1. A prefix decrement (--)
  2. A logical not (!)

This causes pending to be decremented and then tested to see if it's zero.

Solution 3 - Javascript

A number of answers describes what this command does, but not why it is done that way here.

I come from the C world, and I read !--pending as "count down pending and check if it is zero" without really thinking about it. It is an idiom that I think programmers in similar languages should know.

The function uses readdir to get a list of files and subdirectories, which I will collectively call "entries".

The variable pending keeps track of how many of these remains to be processed. It starts out as the length of the list, and counts downward towards zero as each entry is processed.

These entries may be processed out of order, which is why it is necessary to count down rather than just using a simple loop. When all the entries have been processed the callback done is called to notify the original caller of this fact.

In the first call to done is prepended with return, not because we want to return a value, but simply to make the function stop executing at that point. It would have been cleaner code to drop the return and put the alternative in an else.

Solution 4 - Javascript

It's a shorthand.

! is "not".

-- decrements a value.

So !-- checks if the value obtained from negating the result of decrementing a value is false.

Try this:

var x = 2;
console.log(!--x);
console.log(!--x);

The first is false, since the value of x is 1, the second is true, since the value of x is 0.

Side note: !x-- would check if x is false first, and then decrement it.

Solution 5 - Javascript

! is the JavaScript NOT operator

-- is a pre-decrement operator. So,

x = 1;
if (!x) // false
if (!--x) // becomes 0 and then uses the NOT operator,
          // which makes the condition to be true

Solution 6 - Javascript

if(!--pending)

means

if(0 == --pending)

means

pending = pending - 1;
if(0 == pending)

Solution 7 - Javascript

It's the not operator followed by the in-place pre-decrementer.

So if pending was an integer with a value of 1:

val = 1;
--val; // val is 0 here
!val // evaluates to true

Solution 8 - Javascript

#Explanation

This is 2 operators, a ! and a --

!--x 

So, the -- decrements x by 1, then the ! returns true if x is now 0 (or NaN...), false if it isn't. You might read this idiom something like "we decrement x and if that makes it zero..."

If you wanted to make it more readable, you can:

var x = 1
x = x - 1   
if(!x){ //=> true
    console.log("I understand `!--` now!") 
}
x //=> 0

#Try it out:

/* This is an example of the above, you can read this, but it is not needed for !-- */function interactive(a){$("span.code").keydown(function(e){if(13==(e.keyCode||e.which)){var t=$(this);t.clone().html("code").insertAfter(t.next().next()).show().focus().after(template.clone().removeClass("result-template").show()).next().after("<br>"),interactive(),e.preventDefault()}}).keyup(function(e){13!=(e.keyCode||e.which)&&run()})}var template=$(".result-template").hide(),code=$("span.code");code.attr("contenteditable","true").each(function(e,t){template.clone().removeClass("result-template").insertAfter(t)}),interactive(),$.fn.reduce=[].reduce;function run(){var b=!1,context={};$("span.code").each(function(){var a=$(this),res=a.next().show().removeClass("error");try{with(context)res.html(b?"":"  //=> "+eval(a.text()))}catch(e){b=e,res.html("  Error: "+b.message).addClass("error")}})};run();

/* This is an example of the above, you can read this, but it is not needed for !-- */span.result.error{display:block;color:red}.code{min-width:10px}body{font-family:Helvetica,sans-serif}

<!-- This is an example of the above, you can read this, but it is not needed for `!--` --><span class="result result-template"> //=> unknown </span> <h2>Edit This Code:</h2><code><span class="code">x = 1</span><br><span class="code">!--x</span><br><span class="code"> x </span><br></code> <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

Fiddle (Try Out Code)

Solution 9 - Javascript

It merely decreases pending by one and obtains its logical complement (negation). The logical complement of any number different than 0 is false, for 0 it is true.

Solution 10 - Javascript

The real problem here is the lack of a space between the two operators ! and --.

I don't know why people get it in their heads that you can't ever use a space after the ! operator. I think it comes from rigid application of mechanical whitespace rules instead of common sense. Just about every coding standard I've seen prohibits spaces after all unary operators, but why?

If there were ever a case where you clearly need that space, this is one.

Consider this bit of code:

if (!--pending)
    done(null, results);

Not only are ! and -- mashed together, you've got that ( slammed against them too. No wonder it's hard to tell what is connected to what.

A bit more whitespace makes the code much more clear:

if( ! --pending )
    done( null, results );

Sure, if you're used to mechanical rules like "no space inside parens" and "no space after a unary operator", this may seem a bit foreign.

But look at how the extra whitespace groups and separates the various parts of the if statement and expression: You've got --pending, so the -- is clearly its own operator and is tied closely to pending. (It decrements pending and returns the decremented result.) Then you've got the ! separated from that so it's obviously a distinct operator, negating the result. Finally, you've got if( and ) surrounding the whole expression to make it an if statement.

And yes, I removed the space between if and (, because the ( belongs to the if. This ( isn't part of some kind of (!-- syntax as it appears to be in the original, the ( if part of the syntax of the if statement itself.

The whitespace here serves to communicate the meaning, instead of following some mechanical coding standard.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionKieran EView Question on Stackoverflow
Solution 1 - JavascriptTbWill4321View Answer on Stackoverflow
Solution 2 - JavascriptAmitView Answer on Stackoverflow
Solution 3 - JavascriptStig HemmerView Answer on Stackoverflow
Solution 4 - JavascriptLucasView Answer on Stackoverflow
Solution 5 - JavascriptSterling ArcherView Answer on Stackoverflow
Solution 6 - Javascriptjames turnerView Answer on Stackoverflow
Solution 7 - JavascriptBrendan AbelView Answer on Stackoverflow
Solution 8 - JavascriptBen AubinView Answer on Stackoverflow
Solution 9 - JavascriptMinusFourView Answer on Stackoverflow
Solution 10 - JavascriptMichael GearyView Answer on Stackoverflow