Why doesn't Java have compound assignment versions of the conditional-and and conditional-or operators? (&&=, ||=)
Solution 1
Reason
The operators &&=
and ||=
are not available on Java because for most of the developers these operators are:
- error-prone
- useless
Example for &&=
If Java allowed &&=
operator, then that code:
bool isOk = true; //becomes false when at least a function returns false
isOK &&= f1();
isOK &&= f2(); //we may expect f2() is called whatever the f1() returned value
would be equivalent to:
bool isOk = true;
if (isOK) isOk = f1();
if (isOK) isOk = f2(); //f2() is called only when f1() returns true
This first code is error-prone because many developers would think f2()
is always called whatever the f1() returned value. It is like bool isOk = f1() && f2();
where f2()
is called only when f1()
returns true
.
If the developer wants f2()
to be called only when f1()
returns true
, therefore the second code above is less error-prone.
Else &=
is sufficient because the developer wants f2()
to be always called:
Same example but for &=
bool isOk = true;
isOK &= f1();
isOK &= f2(); //f2() always called whatever the f1() returned value
Moreover, the JVM should run this above code as the following one:
bool isOk = true;
if (!f1()) isOk = false;
if (!f2()) isOk = false; //f2() always called
Compare &&
and &
results
Are the results of operators &&
and &
the same when applied on boolean values?
Let's check using the following Java code:
public class qalcdo {
public static void main (String[] args) {
test (true, true);
test (true, false);
test (false, false);
test (false, true);
}
private static void test (boolean a, boolean b) {
System.out.println (counter++ + ") a=" + a + " and b=" + b);
System.out.println ("a && b = " + (a && b));
System.out.println ("a & b = " + (a & b));
System.out.println ("======================");
}
private static int counter = 1;
}
Output:
1) a=true and b=true
a && b = true
a & b = true
======================
2) a=true and b=false
a && b = false
a & b = false
======================
3) a=false and b=false
a && b = false
a & b = false
======================
4) a=false and b=true
a && b = false
a & b = false
======================
Therefore YES we can replace &&
by &
for boolean values ;-)
So better use &=
instead of &&=
.
Same for ||=
Same reasons as for &&=
:
operator |=
is less error-prone than ||=
.
If a developer wants f2()
not to be called when f1()
returns true
, then I advice the following alternatives:
// here a comment is required to explain that
// f2() is not called when f1() returns false, and so on...
bool isOk = f1() || f2() || f3() || f4();
or:
// here the following comments are not required
// (the code is enough understandable)
bool isOk = false;
if (!isOK) isOk = f1();
if (!isOK) isOk = f2(); //f2() is not called when f1() returns false
if (!isOK) isOk = f3(); //f3() is not called when f1() or f2() return false
if (!isOK) isOk = f4(); //f4() is not called when ...
Solution 2
Probably because something like
x = false;
x &&= someComplexExpression();
looks like it ought to be assigning to x
and evaluating someComplexExpression()
, but the fact that the evaluation hinges on the value of x
isn't apparent from the syntax.
Also because Java's syntax is based on C, and no one saw a pressing need to add those operators. You'd probably be better off with an if statement, anyway.
Solution 3
It is this way in Java, because it is this way in C.
Now the question why it is so in C is because when & and && became different operators (sometime preceding C's descent from B), the &= variety of operators was simply overlooked.
But the second part of my answer does not have any sources to back it up.
Solution 4
Largely because Java syntax is based on C (or at least the C family), and in C all those assignment operators get compiled to arithmetic or bitwise assembly instructions on a single register. The assignment-operator version avoids temporaries and may have produced more efficient code on early non-optimising compilers. The logical operator (as they are termed in C) equivalents (&&=
and ||=
) don't have such an obvious correspondence to single assembly instructions; they usually expand to a test and branch sequence of instructions.
Interestingly, languages like ruby do have ||= and &&=.
Edit: terminology differs between Java and C
Solution 5
One of Java's original aims was to be "Simple, Object Oriented, and Familiar." As applied to this case, &= is familiar (C, C++ have it and familiar in this context meant familiar to someone who knows those two).
&&= would not be familiar, and it would not be simple, in the sense that the language designers were not looking to think of every operator they could add to the language, so less extra operators are simpler.
polygenelubricants
I mostly contributed in [java] and [regex] from February to August of 2010. I work for Palantir Technologies now, so I may not have much time on stackoverflow as I did then. We're currently hiring; you can e-mail me for a referral. A few habits I've developed on the site: I will no longer cast a downvote. It will stay at 54 forever. I don't like to engage in dramas on stackoverflow. If you really need to discuss politics and other non-technical issues with me, bring it to meta. I delete my comments once they've become obsolete I try to revise my answers periodically, so I prefer that you leave comments and feedbacks instead of editing my answers directly.
Updated on June 19, 2022Comments
-
polygenelubricants almost 2 years
So for binary operators on booleans, Java has
&
,|
,^
,&&
and||
.Let's summarize what they do briefly here:
- JLS 15.22.2 Boolean Logical Operators &, ^, and |
- JLS 15.23 Conditional-And Operator &&
- JLS 15.24 Conditional-Or Operator ||
For
&
, the result value istrue
if both operand values aretrue
; otherwise, the result isfalse
.For
|
, the result value isfalse
if both operand values arefalse
; otherwise, the result istrue
.For
^
, the result value istrue
if the operand values are different; otherwise, the result isfalse
.The
&&
operator is like&
but evaluates its right-hand operand only if the value of its left-hand operand istrue
.The
||
operator is like|
, but evaluates its right-hand operand only if the value of its left-hand operand isfalse
.Now, among all 5, 3 of those have compound assignment versions, namely
|=
,&=
and^=
. So my question is obvious: why doesn't Java provide&&=
and||=
as well? I find that I need those more than I need&=
and|=
.And I don't think that "because it's too long" is a good answer, because Java has
>>>=
. There must be a better reason for this omission.
From 15.26 Assignment Operators:
There are 12 assignment operators; [...]
= *= /= %= += -= <<= >>= >>>= &= ^= |=
A comment was made that if
&&=
and||=
were implemented, then it would be the only operators that do not evaluate the right hand side first. I believe this notion that a compound assignment operator evaluates the right hand side first is a mistake.From 15.26.2 Compound Assignment Operators:
A compound assignment expression of the form
E1 op= E2
is equivalent toE1 = (T)((E1) op (E2))
, whereT
is the type ofE1
, except thatE1
is evaluated only once.As proof, the following snippet throws a
NullPointerException
, not anArrayIndexOutOfBoundsException
.int[] a = null; int[] b = {}; a[0] += b[-1];
-
EFraim over 14 yearsBut then C/Java was never meant to be beautiful.
-
Yishai over 14 yearsJava supports <<=, >>= and >>>=, so that isn't strictly true.
-
zzawaideh over 14 yearstrue. I didn't think of those. I guess the only explanation is then how frequently it is used.
-
polygenelubricants about 14 yearsI believe you mean the conditional operator equivalents don't have such obvious correspondence. In JLS terminology, the boolean logical operators are
&
,|
and^
;&&
and||
are the conditional operators. -
polygenelubricants about 14 yearsI think this is not a good answer, because one can argue that
x() && y()
looks like it ought to evaluate both sides of the expression. Obviously people accept that&&
is short-circuiting, so that should also follows to&&=
as well. -
PSpeed about 14 years@jleedev, agreed. I believe in these situations it's important to remember that this isn't the equivalent of x = x && someComplexExpression() but the equivalent of x = someComplexExpression() && x. The right-hand side will/should be evaluated first to be consistent with every other assignment operator. And given that, &&= would have no different behavior than &=.
-
MaddTheSane about 14 years@polygene That's fair. How something looks is based on what you're familiar with, though, and I guess they didn't want to add anything new. One thing I like about C/C++/Java/C# is that the basic syntax of expressions is nearly identical.
-
polygenelubricants about 14 years@PSpeed, you are mistaken. The JLS is very clear on what the compound assignment is supposed to do. See my addition above.
-
p00ya about 14 yearsIn C terminology, && and || are "logical operators", s6.5.13-14 in ISO 9899:1999. The bitwise operators are only "logical" when applied to a single bit (a boolean in java); there is no single-bit type in C and the logical operators there apply to all scalar types.
-
polygenelubricants about 14 yearsI think saying that they aren't there because the designers simply followed the precedence set by C is misleading, since they did add
>>>
and>>>=
, which are entirely new. -
David Thornley about 14 years@PSpeed: In that case,
a -= b;
would work entirely differently froma &&= b;
. -
oHo about 12 yearsHi @StriplingWarrior. I have checked with my colleague Yannick, our best Java expert. I have updated my answer using the Java code source used to check that point. As you said
&
and&&
give the same results. Thank you very much for your feedback. Do you like my answer? Cheers. -
adventurerOK almost 12 yearsWhat if I want to do this very fast? &&= would be faster than &=, if it existed, so you should use
if (a) a = b
for speed -
oHo almost 12 yearsHi @adventurerOK. Sorry I am not sure to understand what you mean... I think
a&=b;
is faster thanif(a) a=b;
when using values stored within the CPU registers. However, ifb
is in external memory (not cached), thenif(a) a=b;
is faster. Is it what you mean? Please provide more example code ;-) I am curious about your opinion. See you. Cheers -
Tor Klingberg almost 11 yearsI don't agree when you say "And this is not what we want." If I write
isOK &&= f2();
I would want it to short circuit just like&&
does. -
oHo almost 11 yearsThanks @TorKlingberg for your feedback. I am just realizing that people may think different! All right, I update my answer ;) Cheers
-
Radiodef almost 9 yearsFor that loop you probably just want to do
if (fn(item)) { bVal = true; break; }
. -
Franz B. almost 9 yearsI do not agree with your claim that the operators would be error-prone or useless. Using compound assignments is something you do to take a shortcut for the usual
A = A op B
, so everyone perfectly knows what they are doing and can care for the implications themselves. If your reasons were indeed the cause for its absence, I would see it as unwanted patronizing. However, I wanna thank you for adding the linebool isOk = f1() || f2() || f3() || f4();
because that's what I was to blind to see myself. -
oHo almost 9 yearsThanks @FranzB. for your feedback: you are right. I will update the answer soon (no enough time at the moment to deeply enter in this topic) Cheers ;-)
-
fishinear about 7 yearsYour multiple lines with if statements are a lot LESS understandable: it is not clear anymore that it is a simple or-expression. For the same reason,
if (!f1()) isOk = false;
is less understandable thanisOk &&= f1();
-
asgs about 7 yearsI'd barely consider
&&=
to be ugly -
UKMonkey about 5 yearsOn the funny side - the question was recently asked in the C forum; and this answer was linked (though not marked duplicate) Which makes completes the circular argument!
-
v.oddou about 4 yearsbefore C99, C didn't even have a
bool
type. That's 20 years in the language history with no bool. There was no reason to have&&=
. bitwise operations were enough. -
Elmar Zander over 2 years+1 The only answer that really makes sense. There are no deeper reasons for the lack of those operators than Java's C heritage. C was (and largely still is) just a "high level assembler", and from this perspective there was no need for those operators, since they would not compile into more efficient machine code.