++ operator returns original value if placed after operand — how? - javascript

As far as I've been led to understand, x++ is essentially a terser way of saying x = x + 1. So far, so clear. In front-end Javascript, I've occasionally seen ++x — I seem to remember from a jsPerf test I can no longer find (how does one Google ++ effectively?) that this somehow had a small performance benefit in a particular version of IE, and let it go at that.
However I've recently encountered something that speaks of a weird quirk in execution order (JS code):
var x = 1;
console.log(x++); // 1 (?!)
console.log(x); // 2
…whereas
var x = 1;
console.log(++x); // 2 (what I would've expected)
console.log(x); // 2
I can't get my head around this. How can we return the unmodified variable when the operation and assignment are within the parenthesis, and thus by all rights should be executed before console.log is even invoked, let alone executed and returned?

Those are two different things
x++
is a post-increment. It returns x before the change but then changes it:
tmp = x;
x = x+1;
return tmp;
whereas
++x
is a pre-increment. It first changes x and returns the new value afterwards:
x = x+1;
return x;
The second one is also slightly faster as your compliler/interpreter doesn't need to create a temporary variable and copy the data across.

x++ gets the value, then increments it.
++x increments the value, then gets it.
This is the behavior in every language I've used that supports these operators.

Using ++ AFTER the variable increments the value after that line of code.
Likewise, using ++ BEFORE the variable increments the value before using it in that line of code.
Cool huh?
var x = 1;
x++;
console.log(x++); // 2 (?!)
console.log(x); // 3
console.log(++x); // 4
console.log(x++); // 4
console.log(x); // 5

You're talking about the difference between the pre- and post- increment operators. In the pre- case, the operation is essentially (x = x + 1; yield x), and in the second case it's (yield x; x = x + 1).

Related

Why doesn't short hand decleration work in a for of loop JS

const charCount = {}
for (const char of modString1){
// if (charCount[char] === undefined) charCount[char] = 1
// else charCount[char]++
charCount[char] = charCount[char]++ || 1
}
So I have this for loop that I am iterating over each character of a string to generate the number of times it repeats. The commented out code works. My understanding charCount[char] = charCount[char]++ || 1 is the same but the code doesn't work it always returns 1 for every character. I have also tried the ternary operators as well with the same result. Anyone have answer to this quirk?
If x starts at 0, then x = x++ || 1 will always set x to 1, never allowing it to advance further. This is because the result of x++ is x before incrementing, which is 0 on the first invocation, so the || 1 kicks in and the entire right-hand side evaluates to 1.
The second (and every subsequent) time through, x++ || 1 is always 1; even though x++ then sets x to 2, you're setting it back to 1 when the assignment operator is evaluated (because again, x++ evaluates to whatever x was before being incremented).
You need x = (x + 1) || 1.
The fundamental problem here is that you're effectively doing x = x++. This is a weird and incorrect thing to do. You're taking a simple assignment, and turning it into two assignments: x++ is itself an assignment, it mutates x, and you're mixing this with a second assignment, which mutates x a second time, undoing the first assignment. One of those mutations should not exist. You should typically see x++ as a statement, or x = x + 1 as a statement, but not both together, that is almost always incorrect.
Don't use ++ here. It's the wrong place for it, it's not the tool for your job.
As user229044 answered, assignments of form x = x++ are redundant, because we are effectively discarding the increment. This is because a postfix increment evaluates to its old value.
Your assignment can therefore be rewritten as: x = x || 1 or in words, if x is falsy set it to 1.
This is not the intended behaviour.
If we refactor your commented out if-statement, we can more easily see a pattern behind it:
if (x === undefined) x = 0;
x++;
As you can see, we want to treat the nullish undefined as zero, and always increment (upon finding a certain character).
Your final code may look like:
x = (x || 0) + 1;
Sidenote: Your if-statement only fell back when x was undefined, but your refactor fell back when x was falsy, which has broader meaning. This is technically irrelevant since x is always either a number or undefined. But using the nullish coalescing operator ?? instead of the OR operator || conveys our original intention more clearly: x = (x ?? 0) + 1
Note that converting undefined to a number results in NaN. Because NaN is falsy, the OR operator || will replace it with 1 as intended regardless (cite: user229044's comment). Therefore, using a prefix increment works too:
x = ++x || 1;

Difference between p++ and ++p when using that in a for loop Javascript

This could be a very naive dumb question, but what is the difference in the output of the following 2 condition:
for (var p=0; p<3; p++) {console.log(p)}
//outputs:
0
1
2
for (var p=0; p<3; ++p) {console.log(p)}
//outputs:
0
1
2
'p' result into same output regardless whether I increment the value first and then print it or vice vera. also I do understand the diff between (p++) and (++p), but in this case I'm unable to understand whether at this point in looping will it make it any difference if I were I do either of 2 or if it does make difference how would that impact my program.
Can someone please explain.
Thank
If you dont use the values, after using pre- and post-fix, there is absolutely no difference at all. (exept from performance)
Doing something like this would behave differently, as you can see:
var a = 0;
var b = 0;
var arr = [0,1,2];
console.log(arr[++b]);
console.log(arr[b++]);
console.log(arr[b]);
In this case there is no difference whatsoever as you are not using the value of the expression.
Since you're not assigning the expression to anything, there's no difference apart from a slight performance gain in the pre-incrementer (because a temporary variable is created in order to store the multiple values of p with the post-incrementer). JSBEN.CH.
Just so you know the difference between them:
let var1 = 3;
let var2 = 4;
console.log(var1++); //Outputs the value of var1, then increments it
console.log(++var2); //Increments the value of var2, then outputs it
The += syntax is actually better in this case, because it is easier to read, and it is just a compaction of p = p + 1 - literally no difference, performance-wise or otherwise. This means it's actually faster.
If you put the two plus in front or after the variable/number only makes a different for evaluating it.
Because it is only inportant that the counter is incremented after leaving the block. If this is done before or after doesnt matter. At the end of the call the number is incremented equally.
++p first it will count +1 and then return the result
p++ it will return the value and then add +1
p value will be different at the end of each turn in those 2 cases.
In your example there is no difference.
However if you use the increment ++ or decrement -- operators inside a function the positioning is significant. To quote the article
JavaScript Increment ++ and Decrement --
If the operand is after the variable console.log displays a then it is incremented
let a = 1;
console.log(a++); // 1
console.log(a); // 2
If the operand is before the variable a it is incremented then console.log displays it
let a = 1;
console.log(++a); // 2
console.log(a); // 2
Several other languages such as C and C++ have the same behaviour.
However these operators need to be used with care. See the following stackoverflow answer (albeit it refers to JavaScript, but also applies to C etc)
Why avoid increment (“++”) and decrement (“--”) operators in JavaScript?
In this case there is no difference in pre and post increment.
However in some cases like this can be significant:
here n and i are first evaluated and then incremented
var n=0
var i
for(i=0;n<5;n=i++){}
after the loop n and i look like this: n=5, i=6
here n and i are evaluated first, but i is incremented before entering the cycle
var n=0
var i
for(i=0;n<5;n=++i){}
after the loop n and i look like this: n=5, i=5

Why does (x += x += 1) evaluate differently in C and Javascript?

If the value of the variable x is initially 0, the expression x += x += 1 will evaluate to 2 in C, and to 1 in Javascript.
The semantics for C seems obvious to me: x += x += 1 is interpreted as x += (x += 1) which is, in turn, equivalent to
x += 1
x += x // where x is 1 at this point
What is the logic behind Javascript's interpretation? What specification enforces such behaviour? (It should be noted, by the way, that Java agrees with Javascript here).
Update:
It turns out the expression x += x += 1 has undefined behaviour according to the C standard (thanks ouah, John Bode, DarkDust, Drew Dormann), which seems to spoil the whole point of the question for some readers. The expression can be made standards-compliant by inserting an identity function into it as follows: x += id(x += 1). The same modification can be made to the Javascript code and the question still remains as stated. Presuming that the majority of the readers can understand the point behind "non-standards-compliant" formulation I'll keep it as it is more concise.
Update 2: It turns out that according to C99 the introduction of the identity function is probably not solving the ambiguity. In this case, dear reader, please regard the original question as pertaining to C++ rather than C99, where "+=" can be most probably now safely be regarded as an overloadable operator with a uniquely defined sequence of operations. That is, x += x += 1 is now equivalent to operator+=(x, operator+=(x, 1)). Sorry for the long road to standards-compliance.
x += x += 1; is undefined behavior in C.
The expression statement violates sequence points rules.
(C99, 6.5p2) "Between the previous and next sequence point an object shall have its stored value modified at most once by the evaluation of an expression."
JavaScript and Java have pretty much strict left-to-right evaluation rules for this expression. C does not (even in the version you provided that has the identity function intervening).
The ECMAScript spec I have (3rd Edition, which I'll admit is quite old – the current version can be found here: http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf) says that compound assignment operators are evaluated like so:
11.13.2 Compound Assignment ( op= )
The production AssignmentExpression : LeftHandSideExpression # =
AssignmentExpression, where# represents one of the operators indicated
above, is evaluated as follows:
Evaluate LeftHandSideExpression.
Call GetValue(Result(1)).
Evaluate AssignmentExpression.
Call GetValue(Result(3)).
Apply operator # to Result(2) and Result(4).
Call PutValue(Result(1), Result(5)).
Return Result(5)
You note that Java has the same behavior as JavaScript – I think its spec is more readable, so I'll post some snippets here (http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.7):
15.7 Evaluation Order
The Java programming language guarantees that the operands of
operators appear to be evaluated in a specific evaluation order,
namely, from left to right.
It is recommended that code not rely crucially on this specification.
Code is usually clearer when each expression contains at most one side
effect, as its outermost operation, and when code does not depend on
exactly which exception arises as a consequence of the left-to-right
evaluation of expressions.
15.7.1 Evaluate Left-Hand Operand First The left-hand operand of a binary operator appears to be fully evaluated before any part of the
right-hand operand is evaluated. For example, if the left-hand operand
contains an assignment to a variable and the right-hand operand
contains a reference to that same variable, then the value produced by
the reference will reflect the fact that the assignment occurred
first.
...
If the operator is a compound-assignment operator (§15.26.2), then
evaluation of the left-hand operand includes both remembering the
variable that the left-hand operand denotes and fetching and saving
that variable's value for use in the implied combining operation.
On the other hand, in the not-undefined-behavior example where you provide an intermediate identity function:
x += id(x += 1);
while it's not undefined behavior (since the function call provides a sequence point), it's still unspecified behavior whether the leftmost x is evaluated before the function call or after. So, while it's not 'anything goes' undefined behavior, the C compiler is still permitted to evaluate both x variables before calling the id() function, in which case the final value stored to the variable will be 1:
For example, if x == 0 to start, the evaluation could look like:
tmp = x; // tmp == 0
x = tmp + id( x = tmp + 1)
// x == 1 at this point
or it could evaluate it like so:
tmp = id( x = x + 1); // tmp == 1, x == 1
x = x + tmp;
// x == 2 at this point
Note that unspecified behavior is subtly different than undefined behavior, but it's still not desirable behavior.
In C, x += x += 1 is undefined behavior.
You can not count on any result happening consistently because it is undefined to try to update the same object twice between sequence points.
At least in C, this is undefined behavior. The expression x += x+= 1; has two sequence points: an implicit one right before the expression starts (that is: the previous sequence point), and then again at the ;. Between these two sequence points x is modified twice and this explicitly stated as undefined behavior by the C99 standard. The compiler is free to do anything it likes at this point, including making daemons fly out of your nose. If you're lucky, it simply does what you expect but there is simply no guarantee for that.
This is the same reason why x = x++ + x++; is undefined in C. See also the C-FAQ for more examples and explanations of this or the StackOverflow C++ FAQ entry Undefined Behavior and Sequence Points (AFAIK the C++ rules for this are the same as for C).
Several issues are at play here.
First and most important is this part of the C language specification:
6.5 Expressions
...
2 Between the previous and next sequence point an object shall have its stored value
modified at most once by the evaluation of an expression.72) Furthermore, the prior value
shall be read only to determine the value to be stored.73)
...
72) A floating-point status flag is not an object and can be set more than once within an expression.
73) This paragraph renders undefined statement expressions such as
i = ++i + 1;
a[i++] = i;
while allowing
i = i + 1;
a[i] = i;
Emphasis mine.
The expression x += 1 modifies x (side effect). The expression x += x += 1 modifies x twice without an intervening sequence point, and it's not reading the prior value only to determine the new value to be stored; hence, the behavior is undefined (meaning any result is equally correct). Now, why on Earth would that be an issue? After all, += is right-associative, and everything's evaluated left-to-right, right?
Wrong.
3 The grouping of operators and operands is indicated by the syntax.74) Except as specified
later (for the function-call (), &&, ||, ?:, and comma operators), the order of evaluation
of subexpressions and the order in which side effects take place are both unspecified.
...
74) The syntax specifies the precedence of operators in the evaluation of an expression, which is the same
as the order of the major subclauses of this subclause, highest precedence first. Thus, for example, the
expressions allowed as the operands of the binary + operator (6.5.6) are those expressions defined in
6.5.1 through 6.5.6. The exceptions are cast expressions (6.5.4) as operands of unary operators
(6.5.3), and an operand contained between any of the following pairs of operators: grouping
parentheses () (6.5.1), subscripting brackets [] (6.5.2.1), function-call parentheses () (6.5.2.2), and
the conditional operator ?: (6.5.15).
Emphasis mine.
In general, precedence and associativity do not affect order of evaluation or the order in which side effects are applied. Here's one possible evaluation sequence:
t0 = x + 1
t1 = x + t0
x = t1
x = t0
Oops. Not what we wanted.
Now, other languages such as Java and C# (and I'm assuming Javascript) do specify that operands are always evaluated left-to-right, so there's always a well-defined order of evaluation.
All JavaScript expressions are evaluated left to right.
The associativity of...
var x = 0;
x += x += 1
will be...
var x = 0;
x = (x + (x = (x + 1)))
So because of its left to right evaluation, the current value of x will be evaluated before any other operation takes place.
The result could be viewed like this...
var x = 0;
x = (0 + (x = (0 + 1)))
...which will clearly equal 1.
So...
var x = 0;
x = (x + (x = (x + 1)));
// x = (0 + (x = (0 + 1))); // 1
x = (x + (x = (x + 1)));
// x = (1 + (x = (1 + 1))); // 3
x = (x + (x = (x + 1)));
// x = (3 + (x = (3 + 1))); // 7

Why does +++x gives an error message when +x++ works fine?

var x = null;
+++x generates a ReferenceError, but when I do the same using postfix increment operator +x++, it works just fine.
The LeftHandSideExpression for the ++ operator must not be a number. For instance
1++;
will fail with the same error (invalid increment operand). You can only apply the pre- and postincrement operators on variables/identifiers/expressions.
Since the + sign casts the null value into a number (0), you got the same outcome.
Examples:
var foo = null,
bar = 5;
foo++; // 0
0++; // invalid increment operand
null++; // invalid increment operand
(+bar)++ // invalid increment operand
foo++ +2; // 2
+x++ is split into two steps:
+x initialises x to 0, so it's no longer null.
x++ then increments x, which works since x is no longer null.
+++x is also split into two steps, but in a particular order:
++x is evaluated first, which throws the exception because x is null.
+x would then be evaluated, except you've already had an exception.
I think your assumption was that +++x would be parsed as ++(+x), but it's actually parsed as +(++x). It's an ambiguous-looking syntax, the language designers had to pick one of the two ways to parse it, and from your point of view they chose "the other one".
To be honest, there's absolutely no value in formatting your code this way anyway - all you end up with is dubious-looking code which is destined to confuse people.
if u used the x= 0 ;
x will be initalized with a integer type that will accept the ++x operator while ++(+x)
is like a ++(+null)
so better try to change to X = 0 ;

Javascript variable incrementing in evaluation?

If I have
a = 0;
if(a++ < 1){
console.log(a);
}
I get the value 1 in the console. If a became 1 with the incrementation, then why did the expression evaluate true?
If I do
a = 0;
if(++a < 1){
console.log(a);
}
Then I don't get anything in the console, meaning the expression evaluated to be false.
I have always used variable++ to increment variables in for loops and the like. I have seen the ++variable, but I assumed it was another way to write the same thing. Can someone explain what happens and why? What's the difference between the two?
Does ++variable increment the variable at the time of evaluation, while variable++ increments after?
I have seen the ++variable, but I assumed it was another way to write the same thing.
No, they're not the same at all.
++variable is pre-increment.
It increments variable and evaluates to the new value.
variable++ is post-increment.
It increments variable and evaluates to the old value.
This is common to most C-style languages, including C itself, C++, PHP, Java and Javascript.
i.e.:
Does ++variable increment the variable at the time of evaluation, while variable++ increments after?
Yes, exactly. :)
There's a very important difference here. a++ increments a after evaluation, where ++a increments before evaluation. Conveniently the position of the ++ is either before or after as well, so that's how you can remember which is which.
In other words, this is what you're effectively doing:
a = 0;
if (a < 1)
{
a = a + 1;
console.log(a);
}
else
{
a = a + 1;
}
It is post incrementing, so for the comparison it is 0, then in the block statement it is 1.
a = 0;
// v-----0 < 1
if(a++ < 1){
// now a has been incremented to 1
console.log(a);
}
The pre incrementing version looks like:
a = 0;
// v-----1 < 1
if(++a < 1){
// evaluate to false, so this doesn't run
console.log(a);
}
++var adds one, then does the comparison.
var++ does the comparison, then adds one.
The trick is to remember it by the ++ coming before the variable (increment happens before), or after the variable (increment happens after).

Categories