Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 4 years ago.
Improve this question
I want to toggle a variable between 0 and 1. If it's 0 I want to set it to 1, else if it's 1 I want to set it to 0.
This is such a fundamental operation that I write so often I'd like to investigate the shortest, clearest possible way of doing it. Here's my best so far:
v = (v == 0 ? 1 : 0);
Can you improve on this?
Edit: the question is asking how to write the above statement in the fewest characters while retaining clarity - how is this 'not a real question'? This wasn't intended to be a code-golf exercise, though some interesting answers have come out of people approaching it as golf - it's nice to see golf being used in a constructive and thought-provoking manner.
You can simply use:
v = 1 - v;
This of course assumes that the variable is initialised properly, i.e. that it only has the value 0 or 1.
Another method that is shorter but uses a less common operator:
v ^= 1;
Edit:
To be clear; I never approached this question as code golf, just to find a short way of doing the task without using any obscuring tricks like side effects of operators.
Since 0 is a false value and 1 is a true value.
v = (v ? 0 : 1);
If you are happy to use true and false instead of numbers
v = !v;
or if they must be numbers:
v = +!v; /* Boolean invert v then cast back to a Number */
v = (v + 1) % 2 and if you need to cycle through more values just change 2 for (n + 1). Say you need to cycle 0,1,2 just do v = (v + 1) % 3.
You could write a function for it and use it like:
v = inv(v)
If you don't care about any possibility other than 1:
v = v ? 0 : 1;
In the above case, v will end up being 1 if v is 0, false, undefined or null. Take care using this kind of approach - v will be 0 even if v is "hello world".
Lines like v = 1 - v, or v ^= 1 or v= +!v will all get the job done, but they constitute what I would refer to as hacks. These are not beautiful lines of code, but cheap tricks to have the intended effect. 1 - v does not communicate "toggle the value between 0 and 1". This makes your code less expressive and introduces a place (albeit a small one) where another developer will have to parse your code.
Having instead a function like v = toggle(v) communicates the intent at the quickest glance.
(Honesty and mathematical integrity - given the number of votes on this "answer" - have led me to edit this answer. I held off as long as possible because it was intended as a short quip and not as anything "deep" so putting in any explanation seemed counter to the purpose. However, the comments are making it clear that I should be clear to avoid misunderstanding.)
My original answer:
The wording of this part of the specification:
If it's 0, I want to set it to 1, else set it to 0.
implies that the most accurate solution is:
v = dirac_delta(0,v)
First, the confession: I did get my delta functions confused. The Kronecker delta would have been slightly more appropriate, but not by much as I wanted something that was domain-independent (the Kronecker delta is mainly used just for integers). But I really shouldn't have used delta functions at all, I should have said:
v = characteristic_function({0},v)
Let me clarify. Recall that a function is a triple, (X,Y,f), where X and Y are sets (called the domain and codomain respectively) and f is a rule that assigns an element of Y to each element of X. We often write the triple (X,Y,f) as f: X → Y. Given a subset of X, say A, there is a characteristic function which is a function χA: X → {0,1} (it can also be thought of as a function to a larger codomain such as ℕ or ℝ). This function is defined by the rule:
χA(x) = 1 if x ∈ A and χA(x) = 0 if x ∉ A.
If you like truth tables, it's the truth table for the question "Is the element x of X an element of the subset A?".
So from this definition, it's clear that the characteristic function is what is needed here, with X some big set containing 0 and A = {0}. That's what I should have written.
And so to delta functions. For this, we need to know about integration. Either you already know it, or you don't. If you don't, nothing I can say here will tell you about the intricacies of the theory, but I can give a one sentence summary. A measure on a set X is in essence "that which is needed to make averages work". That is to say that if we have a set X and a measure μ on that set then there is a class of functions X → ℝ, called measurable functions for which the expression ∫X f dμ makes sense and is, in some vague sense, the "average" of f over X.
Given a measure on a set, one can define a "measure" for subsets of that set. This is done by assigning to a subset the integral of its characteristic function (assuming that this is a measurable function). This can be infinite, or undefined (the two are subtly different).
There are lots of measures around, but there are two that are important here. One is the standard measure on the real line, ℝ. For this measure, then ∫ℝ f dμ is pretty much what you get taught in school (is calculus still taught in schools?): sum up little rectangles and take smaller and smaller widths. In this measure, the measure of an interval is its width. The measure of a point is 0.
Another important measure, which works on any set, is called the point measure. It is defined so that the integral of a function is the sum of its values:
∫X f dμ = ∑x ∈X f(x)
This measure assigns to each singleton set the measure 1. This means that a subset has finite measure if and only if it is itself finite. And very few functions have finite integral. If a function has a finite integral, it must be non-zero only on a countable number of points. So the vast majority of functions that you probably know do not have finite integral under this measure.
And now to delta functions. Let's take a very broad definition. We have a measurable space (X,μ) (so that's a set with a measure on it) and an element a ∈ X. We "define" the delta function (depending on a) to be the "function" δa: X → ℝ with the property that δa(x) = 0 if x ≠ a and ∫X δa dμ = 1.
The most important fact about this to get a-hold of is this: The delta function need not be a function. It is not properly defined: I have not said what δa(a) is.
What you do at this point depends on who you are. The world here divides in to two categories. If you are a mathematician, you say the following:
Okay, so the delta function might not be defined. Let's look at its hypothetical properties and see if we can find a proper home for it where it is defined. We can do that, and we end up with distributions. These are not (necessarily) functions, but are things that behave a little like functions, and often we can work with them as if they were functions; but there are certain things that they don't have (such as "values") so we need to be careful.
If you are not a mathematician, you say the following:
Okay, so the delta function might not be properly defined. Who says so? A bunch of mathematicians? Ignore them! What do they know?
Having now offended my audience, I shall continue.
The dirac delta is usually taken to be the delta function of a point (often 0) in the real line with its standard measure. So those who are complaining in the comments about me not knowing my deltas are doing so because they are using this definition. To them, I apologise: although I can wriggle out of that by using the Mathematician's defence (as popularised by Humpty Dumpty: simply redefine everything so that it is correct), it is bad form to use a standard term to mean something different.
But there is a delta function which does do what I want it to do and it is that which I need here. If I take a point measure on a set X then there is a genuine function δa : X → ℝ which satisfies the criteria for a delta function. This is because we are looking for a function X → ℝ which is zero except at a and such that the sum of all of its values is 1. Such a function is simple: the only missing piece of information is its value at a, and to get the sum to be 1 we just assign it the value 1. This is none other than the characteristic function on {a}. Then:
∫X δa dμ = ∑x ∈ X δa(x) = δa(a) = 1.
So in this case, for a singleton set, the characteristic function and the delta function agree.
In conclusion, there are three families of "functions" here:
The characteristic functions of singleton sets,
The delta functions,
The Kronecker delta functions.
The second of these is the most general as any of the others is an example of it when using the point measure. But the first and third have the advantage that they are always genuine functions. The third is actually a special case of the first, for a particular family of domains (integers, or some subset thereof).
So, finally, when I originally wrote the answer I wasn't thinking properly (I wouldn't go so far as to say that I was confused, as I hope I've just demonstrated I do know what I'm talking about when I actually think first, I just didn't think very much). The usual meaning of the dirac delta is not what is wanted here, but one of the points of my answer was that the input domain was not defined so the Kronecker delta would also not have been right. Thus the best mathematical answer (which I was aiming for) would have been the characteristic function.
I hope that that is all clear; and I also hope that I never have to write a mathematical piece again using HTML entities instead of TeX macros!
in general whenever you need to toggle between two values , you can just subtract the current value from the sum of the two toggle values :
0,1 -> v = 1 - v
1,2 -> v = 3 - v
4,5 -> v = 9 - v
You could do
v = Math.abs(--v);
The decrement sets the value to 0 or -1, and then the Math.abs converts -1 to +1.
If it must be the integer 1 or 0, then the way you're doing it is fine, though parentheses aren't needed. If these a are to be used as booleans, then you can just do:
v = !v;
v = v == 0 ? 1 : 0;
Is enough !
List of solutions
There are three solutions I would like to propose. All of them convert any value to 0 (if 1, true etc.) or 1 (if 0, false, null etc.):
v = 1*!v
v = +!v
v = ~~!v
and one additional, already mentioned, but clever and fast (although works only for 0s and 1s):
v = 1-v
Solution 1
You can use the following solution:
v = 1*!v
This will first convert the integer to the opposite boolean (0 to True and any other value to False), then will treat it as integer when multiplying by 1. As a result 0 will be converted to 1 and any other value to 0.
As a proof see this jsfiddle and provide any values you wish to test: jsfiddle.net/rH3g5/
The results are as follows:
-123 will convert to integer 0,
-10 will convert to integer 0,
-1 will convert to integer 0,
0 will convert to integer 1,
1 will convert to integer 0,
2 will convert to integer 0,
60 will convert to integer 0,
Solution 2
As mblase75 noted, jAndy had some other solution that works as mine:
v = +!v
It also first makes boolean from the original value, but uses + instead of 1* to convert it into integer. The result is exactly the same, but the notation is shorter.
Solution 3
The another approach is to use ~~ operator:
v = ~~!v
It is pretty uncommon and always converts to integer from boolean.
To sum up another answer, a comment and my own opinion, I suggest combining two things:
Use a function for the toggle
Inside this function use a more readable implementation
Here is the function which you could place in a library or maybe wrap it in a Plugin for another Javascript Framework.
function inv(i) {
if (i == 0) {
return 1
} else {
return 0;
}
}
And the usage is simply:
v = inv(v);
The advantages are:
No code Duplication
If you or anybody read this again in the future, you will understand your code in a minimum of time.
This is missing:
v = [1, 0][v];
It works as round robin as well:
v = [2, 0, 1][v]; // 0 2 1 0 ...
v = [1, 2, 0][v]; // 0 1 2 0 ...
v = [1, 2, 3, 4, 5, 0][v]; // 0 1 2 3 4 5 ...
v = [5, 0, 1, 2, 3, 4][v]; // 0 5 4 3 2 1 0 ...
Or
v = {0: 1, 1: 0}[v];
The charme of the last solution, it works with all other values as well.
v = {777: 'seven', 'seven': 777}[v];
For a very special case, like to get a (changing) value and undefined, this pattern may be helpful:
v = { undefined: someValue }[v]; // undefined someValue undefined someValue undefined ...
I don't know why you want to build your own booleans? I like the funky syntaxes, but why not write understandable code?
This is not the shortest/fastest, but the most clearest (and readable for everyone) is using the well-known if/else state:
if (v === 0)
{
v = 1;
}
else
{
v = 0;
}
If you want to be really clear, you should use booleans instead of numbers for this. They are fast enough for most cases. With booleans, you could just use this syntax, which will win in shortness:
v = !v;
Another form of your original solution:
v = Number(v == 0);
EDIT: Thanks TehShrike and Guffa for pointing out the error in my original solution.
I would make it more explicit.
What does v mean?
For example when v is some state. Create an object Status. In DDD an value object.
Implement the logic in this value object. Then you can write your code in a more functional way which is more readable. Switching status can be done by creating a new Status based on the current status. Your if statement / logic is then encapsulated in your object, which you can unittest. An valueObject is always immutable, so it has no identity. So for changing it's value you have to create a new one.
Example:
public class Status
{
private readonly int _actualValue;
public Status(int value)
{
_actualValue = value;
}
public Status(Status status)
{
_actualValue = status._actualValue == 0 ? 1 : 0;
}
//some equals method to compare two Status objects
}
var status = new Status(0);
Status = new Status(status);
Since this is JavaScript, we can use the unary + to convert to int:
v = +!v;
This will logical NOT the value of v (giving true if v == 0 or false if v == 1). Then we convert the returned boolean value into its corresponding integer representation.
Another way to do it:
v = ~(v|-v) >>> 31;
One more:
v=++v%2
(in C it would be simple ++v%=2)
ps. Yeah, I know it's double assignment, but this is just raw rewrite of C's method (which doesn't work as is, cause JS pre-increment operator dosen't return lvalue.
If you're guaranteed your input is either a 1 or a 0, then you could use:
v = 2+~v;
Just for kicks: v = Math.pow(v-1,v) also toggles between 1 and 0.
define an array{1,0}, set v to v[v], therefore v with a value of 0 becomes 1, and vica versa.
Another creative way of doing it, with v being equal to any value, will always return 0 or 1
v = !!v^1;
If possible values for v are only 0 and 1, then for any integer x, the expression:
v = Math.pow((Math.pow(x, v) - x), v);
will toggle the value.
I know this is an ugly solution and the OP was not looking for this...but I was thinking about just another solution when I was in the loo :P
Untested, but if you're after a boolean I think var v = !v will work.
Reference: http://www.jackfranklin.co.uk/blog/2011/05/a-better-way-to-reverse-variables
v=!v;
will work for v=0 and v=1; and toggle the state;
If there are just two values, as in this case(0, 1), i believe it's wasteful to use int. Rather go for boolean and work in bits. I know I'm assuming but in case of toggle between two states boolean seems to be ideal choice.
v = Number(!v)
It will type cast the Inverted Boolean value to Number, which is the desired output.
Well, As we know that in javascript only that Boolean comparison will also give you expected result.
i.e. v = v == 0 is enough for that.
Below is the code for that:
var v = 0;
alert("if v is 0 output: " + (v == 0));
setTimeout(function() {
v = 1;
alert("if v is 1 Output: " + (v == 0));
}, 1000);
JSFiddle: https://jsfiddle.net/vikash2402/83zf2zz0/
Hoping this will help you :)
I'm studying for an exam on JavaScript at the moment. I've also got a little knowledge of C and Perl so I'm familiar with prefix and postfix operators in all three languages.
I did an online practice exam for it and one mistake I made was in evaluating the following code:
var x = 10;
x += x--;
Now, I thought it would evaluate to 19 because it would be 10 + 10, then subtract 1 to make 9. But the feedback I got was that it was wrong and it actually evaluates to 20. I thought that sounded a bit suspicious so I tested it out in an HTML document, and it came out with 20 again. I then tried the equivalents in C and Perl and both evaluated to 19.
Can anyone explain to me why JavaScript evaluates the answer as 20 when other languages evaluate it to 19? The answer I got from the test wasn't too clear to me:
The increment ++
and decrement -- operators can be placed
either before or after an operand. If the increment or decrement
operator is placed before the operand, the operation occurs immediately.
If the increment or decrement operator is placed after the operand, the
change in the operand's value is not apparent until the next time the
operand is accessed in the program. Thus the expression x += x-- is equivalent to x = x +
10 which evaluates to 20.
Expanding the statement
x += x--;
to the more verbose JS code
x = x + (function(){ var tmp = x; x = x - 1; return tmp; })();
the result makes perfect sense, as it will evaluate to
x = 10 + (function(){ var tmp = 10; x = 10 - 1; return tmp; })();
which is 20. Keep in mind that JS evaluates expressions left-to-right, including compound assignments, ie the value of x is cached before executing x--.
You could also think of it this way: Assuming left-to-right evaluation order, JS parses the assignment as
x := x + x--
whereas Perl will use
x := x-- + x
I don't see any convincing arguments for or against either choice, so it's just bad luck that different languages behave differently.
In C/C++, every variable can only be changed once in every statement (I think the exact terminology is: only once between two code points, but I'm not sure).
If you write
x += x--;
you are changing the value of x twice:
you are decrementing x using the postfix -- operator
you are setting the value of x using the assignment
Although you can write this and the compiler won't complain about it (not sure, you may want to check the different warning levels), the outcome is undefined and can be different in every compiler.
Basically, the value of x is decemented after assignment. This example might make it clearer (run in Firebug console)
var x = y =10;
x += y--;
console.log(x , y); // outputs 20 9
In C, the line
x += x--;
is undefined behaviour. It seems like your particular compiler is treating it like:
oldx = x--;
x = x + oldx
However, the ECMAScript specification does specify op= - and it gets the value of the left-hand-side before evaluating the right-hand-side.
So it would be equivalent to:
oldx = x--;
x = oldx + oldx
One of the tips for jslint tool is:
++ and --
The ++ (increment) and -- (decrement)
operators have been known to contribute to bad code by
encouraging excessive trickiness. They
are second only to faulty architecture
in enabling to viruses and other
security menaces. There is a plusplus
option that prohibits the use of these
operators.
I know that PHP constructs like $foo[$bar++] may easily result in off-by-one errors, but I couldn't figure out a better way to control the loop than a:
while( a < 10 ) do { /* foo */ a++; }
or
for (var i=0; i<10; i++) { /* foo */ }
Is the jslint highlighting them because there are some similar languages that lack the "++" and "--" syntax or handle it differently, or are there other rationales for avoiding "++" and "--" that I might be missing?
My view is to always use ++ and -- by themselves on a single line, as in:
i++;
array[i] = foo;
instead of
array[++i] = foo;
Anything beyond that can be confusing to some programmers and is just not worth it in my view. For loops are an exception, as the use of the increment operator is idiomatic and thus always clear.
There is a history in C of doing things like:
while (*a++ = *b++);
to copy a string, perhaps this is the source of the excessive trickery he is referring to.
And there's always the question of what
++i = i++;
or
i = i++ + ++i;
actually do. It's defined in some languages, and in other's there's no guarantee what will happen.
Those examples aside, I don't think there's anything more idiomatic than a for loop that uses ++ to increment. In some cases you could get away with a foreach loop, or a while loop that checked a different condtion. But contorting your code to try and avoid using incrementing is ridiculous.
If you read JavaScript The Good Parts, you'll see that Crockford's replacement for i++ in a for loop is i+=1 (not i=i+1). That's pretty clean and readable, and is less likely to morph into something "tricky."
Crockford made disallowing autoincrement and autodecrement an option in jsLint. You choose whether to follow the advice or not.
My own personal rule is to not do anything combined with autoincrement or autodecrement.
I've learned from years of experience in C that I don't get buffer overruns (or array index out of bounds) if I keep use of it simple. But I've discovered that I do get buffer overruns if I fall into the "excessively tricky" practice of doing other things in the same statement.
So, for my own rules, the use of i++ as the increment in a for loop is fine.
In a loop it's harmless, but in an assignment statement it can lead to unexpected results:
var x = 5;
var y = x++; // y is now 5 and x is 6
var z = ++x; // z is now 7 and x is 7
Whitespace between the variable and the operator can lead to unexpected results as well:
a = b = c = 1; a ++ ; b -- ; c; console.log('a:', a, 'b:', b, 'c:', c)
In a closure, unexpected results can be an issue as well:
var foobar = function(i){var count = count || i; return function(){return count++;}}
baz = foobar(1);
baz(); //1
baz(); //2
var alphabeta = function(i){var count = count || i; return function(){return ++count;}}
omega = alphabeta(1);
omega(); //2
omega(); //3
And it triggers automatic semicolon insertion after a newline:
var foo = 1, bar = 2, baz = 3, alpha = 4, beta = 5, delta = alpha
++beta; //delta is 4, alpha is 4, beta is 6
preincrement/postincrement confusion can produce off-by-one errors that are extremely difficult to diagnose. Fortunately, they are also complete unnecessary. There are better ways to add 1 to a variable.
References
JSLint Help: Increment and Decrement Operators
The "pre" and "post" nature of increment and decrement operators can tend to be confusing for those who are not familiar with them; that's one way in which they can be tricky.
Consider the following code
int a[10];
a[0] = 0;
a[1] = 0;
a[2] = 0;
a[3] = 0;
int i = 0;
a[i++] = i++;
a[i++] = i++;
a[i++] = i++;
since i++ gets evaluated twice the output is
(from vs2005 debugger)
[0] 0 int
[1] 0 int
[2] 2 int
[3] 0 int
[4] 4 int
Now consider the following code :
int a[10];
a[0] = 0;
a[1] = 0;
a[2] = 0;
a[3] = 0;
int i = 0;
a[++i] = ++i;
a[++i] = ++i;
a[++i] = ++i;
Notice that the output is the same. Now you might think that ++i and i++ are the same. They are not
[0] 0 int
[1] 0 int
[2] 2 int
[3] 0 int
[4] 4 int
Finally consider this code
int a[10];
a[0] = 0;
a[1] = 0;
a[2] = 0;
a[3] = 0;
int i = 0;
a[++i] = i++;
a[++i] = i++;
a[++i] = i++;
The output is now :
[0] 0 int
[1] 1 int
[2] 0 int
[3] 3 int
[4] 0 int
[5] 5 int
So they are not the same, mixing both result in not so intuitive behavior. I think that for loops are ok with ++, but watch out when you have multiple ++ symbols on the same line or same instruction
In my view, "Explicit is always better than implicit." Because at some point, you may got confused with this increments statement y+ = x++ + ++y. A good programmer always makes his or her code more readable.
I've been watching Douglas Crockford's video on this and his explanation for not using increment and decrement is that
It has been used in the past in other languages to break the bounds of arrays and cause all manners of badness and
That it is more confusing and inexperienced JS developers don't know exactly what it does.
Firstly arrays in JavaScript are dynamically sized and so, forgive me if I'm wrong, it is not possible to break the bounds of an array and access data that shouldn't be accessed using this method in JavaScript.
Secondly, should we avoid things that are complicated, surely the problem is not that we have this facility but the problem is that there are developers out there that claim to do JavaScript but don't know how these operators work?? It is simple enough. value++, give me the current value and after the expression add one to it, ++value, increment the value before giving me it.
Expressions like a ++ + ++ b, are simple to work out if you just remember the above.
var a = 1, b = 1, c;
c = a ++ + ++ b;
// c = 1 + 2 = 3;
// a = 2 (equals two after the expression is finished);
// b = 2;
I suppose you've just got to remember who has to read through the code, if you have a team that knows JS inside out then you don't need to worry. If not then comment it, write it differently, etc. Do what you got to do. I don't think increment and decrement is inherently bad or bug generating, or vulnerability creating, maybe just less readable depending on your audience.
Btw, I think Douglas Crockford is a legend anyway, but I think he's caused a lot of scare over an operator that didn't deserve it.
I live to be proven wrong though...
The most important rationale for avoiding ++ or -- is that the operators return values and cause side effects at the same time, making it harder to reason about the code.
For efficiency's sake, I prefer:
++i when not using the return value (no temporary)
i++ when using the return value (no pipeline stall)
I am a fan of Mr. Crockford, but in this case I have to disagree. ++i is 25% less text to parse than i+=1 and arguably clearer.
Another example, more simple than some others with simple return of incremented value:
function testIncrement1(x) {
return x++;
}
function testIncrement2(x) {
return ++x;
}
function testIncrement3(x) {
return x += 1;
}
console.log(testIncrement1(0)); // 0
console.log(testIncrement2(0)); // 1
console.log(testIncrement3(0)); // 1
As you can see, no post-increment/decrement should be used at return statement, if you want this operator to influence the result. But return doesn't "catch" post-increment/decrement operators:
function closureIncrementTest() {
var x = 0;
function postIncrementX() {
return x++;
}
var y = postIncrementX();
console.log(x); // 1
}
I think programmers should be competent in the language they are using; use it clearly; and use it well. I don't think they should artificially cripple the language they are using. I speak from experience. I once worked literally next door to a Cobol shop where they didn't use ELSE 'because it was too complicated'. Reductio ad absurdam.
In my experience, ++i or i++ has never caused confusion other than when first learning about how the operator works. It is essential for the most basic for loops and while loops that are taught by any highschool or college course taught in languages where you can use the operator. I personally find doing something like what is below to look and read better than something with a++ being on a separate line.
while ( a < 10 ){
array[a++] = val
}
In the end it is a style preference and not anything more, what is more important is that when you do this in your code you stay consistent so that others working on the same code can follow and not have to process the same functionality in different ways.
Also, Crockford seems to use i-=1, which I find to be harder to read than --i or i--
As mentioned in some of the existing answers (which annoyingly I'm unable to comment on), the problem is that x++ ++x evaluate to different values (before vs after the increment), which is not obvious and can be very confusing - if that value is used. cdmckay suggests quite wisely to allow use of increment operator, but only in a way that the returned value is not used, e.g. on its own line. I would also include the standard use within a for loop (but only in the third statement, whose return value is not used). I can't think of another example. Having been "burnt" myself, I would recommend the same guideline for other languages as well.
I disagree with the claim that this over-strictness is due to a lot of JS programmers being inexperienced. This is the exact kind of writing typical of "overly-clever" programmers, and I'm sure it's much more common in more traditional languages and with JS developers who have a background in such languages.
My 2cents is that they should be avoided in two cases:
1) When you have a variable that is used in many rows and you increase/decrease it on the first statement that uses it (or last, or, even worse, in the middle):
// It's Java, but applies to Js too
vi = list.get ( ++i );
vi1 = list.get ( i + 1 )
out.println ( "Processing values: " + vi + ", " + vi1 )
if ( i < list.size () - 1 ) ...
In examples like this, you can easily miss that the variable is auto-incremented/decremented or even remove the first statement. In other words, use it only in very short blocks or where the variable appears in the block on just a couple of close statements.
2) In case of multiple ++ and -- about the same variable in the same statement. It's very hard to remember what happens in cases like this:
result = ( ++x - --x ) * x++;
Exams and professional tests asks about examples like above and indeed I've stumbled upon this question while looking for documentation about one of them, but in real life one shouldn't be forced to think so much about a single line of code.
Is Fortran a C-like language? It has neither ++ nor --. Here is how you write a loop:
integer i, n, sum
sum = 0
do 10 i = 1, n
sum = sum + i
write(*,*) 'i =', i
write(*,*) 'sum =', sum
10 continue
The index element i is incremented by the language rules each time through the loop. If you want to increment by something other than 1, count backwards by two for instance, the syntax is ...
integer i
do 20 i = 10, 1, -2
write(*,*) 'i =', i
20 continue
Is Python C-like? It uses range and list comprehensions and other syntaxes to bypass the need for incrementing an index:
print range(10,1,-2) # prints [10,8.6.4.2]
[x*x for x in range(1,10)] # returns [1,4,9,16 ... ]
So based on this rudimentary exploration of exactly two alternatives, language designers may avoid ++ and -- by anticipating use cases and providing an alternate syntax.
Are Fortran and Python notably less of a bug magnet than procedural languages which have ++ and --? I have no evidence.
I claim that Fortran and Python are C-like because I have never met someone fluent in C who could not with 90% accuracy guess correctly the intent of non-obfuscated Fortran or Python.
The operators mean different things when used as prefixes versus suffixes, which can cause hard-to-find bugs. Consider the following example, using bubbleSort:
function bubbleSort(array) {
if(array.length === 1) return array;
let end = array.length - 2;
do {
for (let i = 0; i < array.length; i += 1) {
if (array[i] > array[i + 1]) {
swap(array, i, i + 1);
}
}
} while (end--);
}
bubbleSort([6,5]);
Let's imagine in the course of running our program, we pass a two-item value into our sort function. The code runs fine as-is: the "do/while" loop first executes before reaching the condition. However, the program sees that end is falsy and exits the loop before decrementing the variable.
Now consider the following code, where the -- symbol is used as a prefix, rather than a suffix. This code will enter an infinite loop:
function bubbleSort(array) {
if(array.length === 1) return array;
let end = array.length - 2;
do {
for (let i = 0; i < array.length; i += 1) {
if (array[i] > array[i + 1]) {
swap(array, i, i + 1);
}
}
} while (--end);
}
bubbleSort([6,5]);
Now when we hit the while condition, we decrement the end value before checking it. This returns -1, which in Javascript, is a truthy value.
I don't have a strong opinion on their use one way or the other, but I just wanted to show how they can cause real bugs when used carelessly.
Argument for ++ is that ++ is not applicable for strings which will cause TypeError, which is almost always preferable.