"Item is null" despite if(item)


#1

I’m having problems with my code. It keeps telling me that I have an error on line 15, which is var itemPos = item.pos;,but I’m not sure what’s wrong.

loop {
var flag = this.findFlag();
var item = this.findNearestItem();
if (flag) {
    var pos = flag.pos;
    var fX = pos.x;
    var fY = pos.y;
    this.moveXY(fX, fY);
    this.buildXY("fire-trap", fX, fY);
    this.pickUpFlag(flag);
} else if (item); {
    var itemPos = item.pos;
    var itemX = itemPos.x;
    var itemY = itemPos.y;
    this.moveXY(itemX, itemY);
    }

}

Thanks!


Drop The Flag Help
#2

This line:

} else if (item); {

Should not contain a semicolon before the opening curly brace. It should be:

} else if (item) {

I don’t see anything wrong besides that. Sometimes the linter gets thrown off a bit.


#3

I apologize in advance, I spent the last three hours explaining stuff and what you read now is exactly what I feel like

Dear J_F_B_M, why is there an error?

if (item);

This line does nothing. It is an empty statement. It is equal to:

if(item) {
    // Do nothing
}

This is because a single ; is a valid JS-Statement. In fact, ;;;;; is a total of 5 statements (which all do nothing).


But J_F_B_M, there is a curly bracket behind that…

Jup, you’re right. In other languages (like Java, which looks similar but is different) this would be important. Here it isn’t (in the same way). The curly brackets enclose a block statement. A block statement encloses zero or more other statements (which can also be more block statements).


But J_F_B_M, why do you tell us this boring stuff?

You haven’t known up until now about it, but you already used block statements quite often. An if-statement can only be followed by one other statement. But sometimes this is not enough, we want multiple statements “inside” an if. The solution: A block statement.


Come on, get to the point. What is my problem?

if (flag) {
    // Bla bla
} else if (item); {
    // More Bla
}

This code is equal to the following code (I added some intendations

if (flag) {
    // Bla bla
} else if (item)
    ;

{
    // More Bla (including var itemPos = item.pos;)
}

As the block statement is unimportant here we could also remove it:

if (flag) {
    // Bla bla
} else if (item)
    ;

// More Bla (including var itemPos = item.pos;)

Now there is definitely a problem.
More Bla is not inside the if. At some point your code will run like this:

Is there a flag?           -> No, go to else
Else, is there an item?    -> No, don't execute the ;-statement

Cool, "if-else" is over, so the next statement is...
"var itemPos = item.pos;"
But "item == null"... better throw a cryptic error instead.

You can see now that even though it looks like it at first you never actually check if item==null (at least not in a meaningful way).


And why did you post that after UltCombos answer?

I started typing first, but needed longer. Also my answer is more exhaustive.


#4

@J_F_B_M Nice explanation! I was not expecting such an extensive answer to this commonplace problem, well done.

By the way, I’d like to add that using “standalone” blocks does not make much sense in JavaScript prior to ECMAScript 2015 (which CodeCombat does not support yet, anyway) as block scoping was not quite supported¹ until then. Quoting MDN:

Although “standalone” blocks are valid syntax, you do not want to use standalone blocks in JavaScript, because they don’t do what you think they do, if you think they do anything like such blocks in C or Java. For example:

var x = 1;
{
  var x = 2;
}
console.log(x); // logs 2

This logs 2 because the var x statement within the block is in the same scope as the var x statement before the block. In C or Java, the equivalent code would have outputted 1.


¹ It is technically possible to (ab)use try/catch blocks’ exception identifier to simulate block scoping, but that is not related to the main topic here. :grin:


#5

Actually I think this is a pretty uncommon problem. Most people do not tend to place semicoli in places where they are syntactically correct but semantically nonsense. And even less people place a semicolon in a place where it actually changes the semantic.


Those two lines (and their surroundings) belong together :smile:


#6

That is true.

Perhaps I didn’t express myself well. I meant that I believe the specific “semicolon between a control flow statement and a block statement” issue to be a common one as virtually every developer has made this mistake sometime in their lives. And this often happens at the very beginning of their learning. That is why I replied with a simple “how to fix it” answer rather than a very detailed one that may overload their beginner programming minds. Borrowing Nick’s words:

(Note: I actually find your answer very comprehensive, detailed and easy to understand, but a complete beginner may find otherwise. Either way, it will be there in case they want to revisit it in the future. It also provides useful insight that helps actually understanding the programming language syntax.)

As for how common this issue really is nowadays, I’m not sure but take in consideration that one of the main reasons for the rise of the OTBS and Stroustrup coding styles is that putting the opening curly brace in the same line as the control flow statement makes it harder to accidentally insert an unwanted semicolon between them.