Why is for(;;){…} an infinite loop? [duplicate] - javascript

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Empty for loop - for(;;)
I just found a strange construct in the JS parser of UglifyJS (at L1045): for(;;){…}.
I assumed that an empty condition would resolve to undefined, which is converted to the boolean value false. But that's definitely not the case.
Apparently, it triggers an infinite loop. I was able to reproduce this behavior, but I have no clue why. Any (logical) explanations?
Besides: When this is possible, why doesn't while(){…} work?

That's just the definition of the semantics. A missing "test" expression is treated as an expression with the value true. Languages are made up by people, and they are at liberty to specify any behavior they like. Clearly, that behavior is something Mr. Eich likes :-)

for(;;){…} interprets an empty condition as true and while(){} is not considered as valid. As said before it's totally language dependant but described in the specification.

In the ECMA-262 language specification of JavaScript (section 12.6.3) it is defined how the behaviour of the for loop should be.
You can see from the definition that if the information around and between the semi-colons is not available, there are no conditions to leave the loop. The only way to leave the loop is by defining a test condition and optionally some start and step values.
The behaviour could be defined in a different way but that's just not how it is.

From the spec.
12.6.3 The for Statement
The production
IterationStatement : for (ExpressionNoIn(opt) ; Expression(opt) ; Expression(opt)) Statement
is evaluated as follows:
1. If ExpressionNoIn is present, then.
a. Let exprRef be the result of evaluating ExpressionNoIn.
b. Call GetValue(exprRef). (This value is not used but the call may have side-effects.)
2. Let V = empty.
3. Repeat
a. If the first Expression is present, then
i. Let testExprRef be the result of evaluating the first Expression.
ii. If ToBoolean(GetValue(testExprRef)) is false, return (normal, V, empty) .
b. Let stmt be the result of evaluating Statement.© Ecma International 2011 91
c. If stmt.value is not empty, let V = stmt.value
d. If stmt.type is break and stmt.target is in the current label set, return (normal, V, empty) .
e. If stmt.type is not continue || stmt.target is not in the current label set, then
i. If stmt is an abrupt completion, return stmt.
f. If the second Expression is present, then
i. Let incExprRef be the result of evaluating the second Expression.
ii. Call GetValue(incExprRef). (This value is not used.
Gist of this spec: for statement stops when first Expression returns "falsey" value.
Since absence of expression doesn't return false, the script will run forever (or until break statement is executed from inside the loop body).

Related

Javascript code snippet explanation [duplicate]

This question already has answers here:
Automatic semicolon insertion & return statements [duplicate]
(3 answers)
Closed 9 years ago.
I have seen this trick question online without any answer or description. Not sure what's going on here:
function identity() {
var name = 'Jack';
alert(name);
return
name
};
var who = identity();
alert(who)
This snipped outputs, jack & then undefined, why?
Change this
return
name
to this:
return name;
The return statement is one of the few places where javascript does not like whitespace. EDIT. What's happening in the original is the browser inserts a semicolon after the return statement, like this
return;
name // this gets ignored
So the return value is undefined.TehShrike links to a very good document explaining the exact rules ECMAAScript environments must follow when ignoring whitespace/line breaks and when semicolons must be inserted.
The ECMAScript standard says this (among other things)
Certain ECMAScript statements (empty statement, variable statement,
expression statement, do-while statement, continue statement, break
statement, return statement, and throw statement) must be terminated
with semicolons. Such semicolons may always appear explicitly in the
source text. For convenience, however, such semicolons may be omitted
from the source text in certain situations. These situations are
described by saying that semicolons are automatically inserted into
the source code token stream in those situations.
identity is a function. who then declares a new instance of that, which we can tell from the func that it will create a local variable name and assign jack to it, then alert.
The function then looks like it return nothing (although name is on the next line, so I'd imagine you want to return that, change to return name;).

Mozilla states expressions are also statements. Why?

Looking at these articles from Mozilla's JavaScript guide:
Expressions
Statements
expressions are also considered assignment statements. In fact, in the second article one can read "any expression is also a statement". Being acquainted with other programming languages, I thought that expressions are always values, but they never cause side effects like statements would do. In other words, 7, 7 + 8, "string", etc., are expressions, because they don't change the state, but a = 7 is a statement, since a variable has now been defined (i.e. a state has changed).
Why would Mozilla not differentiate between the two in JS?
I believe you are taking the terms "expression" and "statement" too literally. "Expressions not changing any state" is a very tough requirement for a programming language.
A thought experiment: In 7 + 8 substitute 8 with a function call to
var globalVar = 0;
function my8() {
globalVar = globalVar + 1;
return 8;
}
Is 7 + my8() a statement or an expression? There is no obvious state change happing here, but still my8 performs a state change. Using the "no side-effects" definition it would be impossible to decide if 7 + my8() is a statement or an expression without analyzing the code of the my8 function. Of course it would be possible to simply prohibit any state change as part of a function call, but that is not the way of JavaScript.
In my experience most languages define "everything which returns a value" as an expression and a statement, everything else as just a statement.
To answer your question "Why would Mozilla not differentiate between the two in JS?":
I think they do, but not in the manner you expected. To consider "everything which returns a value" an expression seems to be the most practical approach.
Also there is no contradiction between a chunk of code being a statement and an expression at the same time. That is simply how Javascript and many other languages work. Of course it is always possible to draw a more strict line between those two.
Examples:
Assignments return values, so this is possible:
a = b = c = 1;
It can be written in the more obvious form:
a = (b = (c = 1));
Because of that an assignment is considered an expression (and also a statement).
On the other hand:
if (true) { };
does not return a value (in Javascript!) and therefore is no expression (but still a statement).
An expression is a code fragment that returns some value, Expression (Computer Science):
3; // 3
{}; // Object
func(); // whatever func returns, or undefined if not specified
You can combine expressions into one compound expression:
3 + 7; // 10
{}, []; // Array. Comma operator always returns result of right-most expression
A statement is the smallest valid code fragment that can be compiled or interpreted, Statement (Computer Science):
5; // valid js
You can also combine statements into compound statements:
check || func(); // valid js
{
4 + 9;
"block statement";
}
In the Mozilla documentation, a statement refers to any (compound) statement that is explicitly or implicitly terminated by semi-colon (;).
[,,[],[,[,,],,]]; // Array declaration whose reference is returned (and ignored)
// Multi-dimensional array with empty (undefined) elements
In some programming languages the above example doesn't compile or doesn't get interpreted. Other languages might not allow for the result of an expression not to be catched.
Javascript is very expressive, which is why every expression counts as a valid statement. Some statements are not expressions, like break, return, while, etc. They don't return any value, but they control the program execution flow.
Mozilla does differentiate between the two, or rather the Javascript syntax does.
The only slightly "special" about Javascript is the following:
"any expression is also a statement",
which means that at places where a statement is required in the syntax, an expression can be used directly (but not the other way around). E.g. the following is valid Javascript but invalid in many other similar languages:
if (true) "asfd"
or
foo = function(){
if (5) {
"some text here that won't do anything";
return true;
42; // always good to have that one here!
}
}
whereas statements cannot be used as expressions:
a = (if (true) 5) // does not work "unexpected token 'if'"
They used that "feature" for the strict mode specification without introducing a new keyword or syntax - if you add the expression "use strict" as the first statement in a function body, Javascript is executed in strict mode in supporting browsers.
While expressions evaluate to a value, usually, statements do not. Most statements alter control flow, expressions usually don't (although one could argue that an expression that results in an exception being thrown alters control flow, too).
In Javascript expressions form a subset of all statements.

How does this "for (;;)" syntax work in Javascript?

I came across a strange syntax for the for in an open source Javascript library.
for (;;) {
}
What does this even do? Can anyone answer?
It's "loop forever" and it works the same in C, C++, C#, Java etc. You've got a for statement with
no init step
no termination check (=> continue forever)
no end-of-loop step
It's an infinite loop, just like while(true).
As others have already pointed out, if will run forever, but you can still end the loop with break. Like:
for (;;) {
if (condition) {
break;
}
}
Mozilla
has a good breakdown of how javascript evaluates for loops:
for ([initialization]; [condition]; [final-expression])
statement
initialization
An expression (including assignment expressions) or variable declaration. Typically used to initialize a counter variable. This
expression may optionally declare new variables with the var keyword.
These variables are not local to the loop, i.e. they are in the same
scope the for loop is in. The result of this expression is discarded.
condition
An expression to be evaluated before each loop iteration. If this expression evaluates to true, statement is executed. This conditional
test is optional. If omitted, the condition always evaluates to true.
If the expression evaluates to false, execution skips to the first
expression following the for construct.
final-expression
An expression to be evaluated at the end of each loop iteration. This occurs before the next evaluation of condition. Generally used to
update or increment the counter variable.
statement
A statement that is executed as long as the condition evaluates to true. To execute multiple statements within the loop, use a block
statement ({ ... }) to group those statements.
Most relevant to this question is in the condition section:
This conditional test is optional. If omitted, the condition always
evaluates to true.
A simple/empty ; in many languages acts as a blank but true (and executable) statement.
Hence, in the for loop, all three expressions are true, always matched and hence, results in an infinite loop.
It has also been on Wikipedia. As per the wiki page
This style is used instead of infinite while(1) loops to avoid a
warning in Visual C++.
The controlling expression of an if statement or while loop evaluates to a constant. If the controlling expression of a while loop is a constant because the loop will exit in the middle, consider replacing the while loop with a for loop. You can omit the initialization, termination test and loop increment of a for loop, which causes the loop to be infinite (like while(1)) and you can exit the loop from the body of the for statement.
This is valid for loop for (;;) {} if condition is not given in for loop its by default true. So loop run infinitely. same as for (;1;) {}
Additionally not only in Javascript its true in C, C# language also etc.
Read this: Is “for(;;)” faster than “while (TRUE)”? If not, why do people use it? to know why some programmers may prefer for (;;) {} over simple while(true){} (interesting)
It runs an infinite loops, because
Essentially, a for loop is a shortened version of another loop, with this syntax
for(a;b;c){
}
is
a;
while(b){
c;
}
so loops forever, since the b is empty, and it has no increment operator to change anything.
Basically, it's an infinite loop of nothingness.
EDIT: Apparently, the empty command evaluates to true.

No semicolon before [] is causing error in JavaScript

var a = [1, 2, 3, 4];
var b = [10, 20, 30, 40];
console.log([a, b].length)
[a, b].some(function(x) {
x.push(x.shift())
});
I was extremely surprised today when this code caused
[a,b].some(function(x){ x.push(x.shift()) });
^
TypeError: Cannot call method 'some' of undefined
Obviously the JavaScript 'auto semicolon insertion' is not working as expected here. But why?
I know you might recommend to use ; everywhere to avoid something like that, but the question is not about whether it is better to use ; or not. I would love to know what exactly happens here?
When I'm worried about semicolon insertion, I think about what the lines in question would look like without any whitespace between them. In your case, that would be:
console.log([a,b].length)[a,b].some(function(x){ etc });
Here you're telling the Javascript engine to call console.log with the length of [a,b], then to look at index [a,b] of the result of that call.
console.log returns a string, so your code will attempt to find property b of that string, which is undefined, and the call to undefined.some() fails.
It's interesting to note that str[a,b] will resolve to str[b] assuming str is a string. As Kamil points out, a,b is a valid Javascript expression, and the result of that expression is simply b.
In general, one could say that implicit semi-colon's can easily fail when defining an array on a new line, because an array defined on a new line is interpreted as a property access of the value of the expression on the previous line.
Javascript does only consider new lines to mark the end of a statement if not ending the statement after this new line would cause a parse error. See What are the rules for JavaScript's automatic semicolon insertion (ASI)? and EcmaScript 5 spec for the exact rules. (Thanks to Rob W and limelights)
What happens is the following:
The code get interpreted as
console.log([a,b].length)[a,b].some(function(x){ x.push(x.shift()) });
i.e. all as one statement.
Now parse the statement:
some is called on the value of console.log([a,b].length)[a,b]
the value of console.log([a,b].length)[a,b] is computed by taking the returned value of console.log([a,b].length) (undefined) and then trying to access the property with the name of the value of a,b.
a,b evaluates to the value of b (try it in your console). There's no property with the value of b of undefined, so the resulting value will be undefined as well.
There's no method some on undefined, hence the error.
JavaScript doesn't treat every line break as a semicolon. It usually treats line
breaks as semicolons only if it can’t parse the code without the semicolons. Basically, JavaScript treats a line break as a semicolon if the next non-space character cannot be interpreted as a continuation of the current statement. JavaScript - The Definitive Guide: 6th Ed. section 2.4
So, in your case, it is interpreting the line as something like
console.log([a,b].length)[a,b].some(function(x){ x.push(x.shift()) });
And that is the reason for error. JavaScript is trying to perform array-access on the results of console.log([a,b].length). Depending on the JavaScript engine and the return value of console.log, you might get different errors.
If it is the last statement of the function or flow, you can avoid ';' but it is recommended to put ';' at the end of the each statement to avoid such error.

Difference between statement and function

It's almost midnight and I just got a question in my head is "for loop" a statement or a function.
I always thought it is a statement, but I did a google search on it being a function and there are indeed results for that. So what is it? And in that case what is the difference between function and statement?
A for loop is a not usually a function, it is a special kind of statement called a flow control structure.
A statement is a command. It does something. In most languages, statements do not return values. Example:
print "Hello World"
A function is a subroutine that can be called elsewhere in the program. Functions often (but not necessarily) return values. Example:
function(a) { return a * 2 }
A control structure, also known as a compound statement, is a statement that is used to direct the flow of execution. Examples:
if (condition) then { branch_1 } else { branch_2 }
for (i = 0; i < 10; i += 1) { ... }
Also worth noting is that an expression is a piece of code that evaluates to a value. Example:
2 + 2
All examples are in pseudocode, not tied to any particular language. Also note that these are not exclusive categories, they can overlap.
Out of the three language tags you've chosen, I'm only very familliar with Python, but I believe many other languages have a similar view of these concepts. All the example code here is Python.
A statement is a thing that is executed; an "instruction to do something" that the language implementation understands. e.g.
print "Hello World"
pass
def foo(n):
return n + 1
if condition:
print 'yay'
else:
print 'doh'
The above block contains a print statement, a pass statement, a function definition statement, and an if/else statement. Note that the function definition and the if/else statement are compound statements; they contain other statements (possibly many of them, and possibly other compound statements).
An expression is something that can be evaluated to produce a value. e.g.
1
"foo"
2 * 6
function(argument)
None
The above contains a numeric literal expression, a string literal expression, an expression involving numeric operators, a function call expression, and the literal None expression. Other than literals and variables, expressions are made up of other expressions. In function(argument), function and argument are also both expressions.
The key difference is that statements are instructions that tell the language implementation to "go do something". Expressions are evaluated to a value (which possibly requires to language implementation to "go do something" on the way).
A consequence of this is that anywhere you see a value (including an expression), you could substitute any other expression and you would still get something that makes some sort of sense. It may fail to compile, or throw exceptions at runtime, or whatever, but on at least some level you can understand what's going on.
A statement can never appear inside an expression (I believe this is not true in Ruby and Javascript in some sense, as they allow literal code blocks and functions which are then used as a value as a whole, and functions and code blocks contain statements; but that's kind of different from what I'm talking about). An expression must have a value (even if it's an uninteresting one like None). A statement is a command; it doesn't make sense for it to appear as part of an expression, because it has no value.
Many languages also allow expressions to be used as statements. The usual meaning of this is "evaluate this expression to get a value, then throw it away". In Python, functions that always return None are usually used this way:
write_to_disk(result)
It's used as a "command", so it looks like a statement, but technically it's an expression, we just don't use the value it evaluates to for anything. You can argue that a "bare expression" is one of the possible statements in a language (and they're often parsed that way).
Some languages though distinguish between functions that must be used like statements with no return value (often called procedures) and functions that are used like an expression, and give you errors or warnings for using a function like a statement, and definitely give you an error for using a procedure as an expression.
So, if foo is an expression, I can write 1 + foo and while it may be result in a type error, it at least makes that much sense. If foo is a statement, then 1 + foo is usually a parse error; the language implementation won't even be able to understand what you're trying to say.
A function on the other hand, is a thing you can call. It's not really either an expression or a statement in itself. In Python, you use a def statement to create a function, and a function call is an expression. The name bound to the function after you create it is also an expression. But the function itself is a value, which isn't exactly an expression when you get technical, but certainly isn't a statement.
So, for loops. This is a for loop in Python:
for thing in collection:
do_stuff(thing)
Looks like a statement (a compound statement, like an if statement). And to prove it, this is utterly meaningless (and a parse error):
1 + for thing in collection:
do_stuff(thing)
In some languages though, the equivalent of a for loop is an expression, and has a value, to which you can attempt to add 1. In some it's even a function, not special syntax baked into the language.
This answer is relevant to Python 2.7.2. Taken from the python tutorial:
"4. More Control Flow Tools
4.2. for Statements:
The for statement in Python differs a bit from what you may be used to in C or Pascal. Rather than always iterating over an arithmetic progression of numbers (like in Pascal), or giving the user the ability to define both the iteration step and halting condition (as C), Python’s for statement iterates over the items of any sequence (a list or a string), in the order that they appear in the sequence."

Categories

Resources