Why doesn't Java have compound assignment versions of the conditional-and and conditional-or operators? (&&=, ||=)

17,402

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.

Share:
17,402
polygenelubricants
Author by

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, 2022

Comments

  • polygenelubricants
    polygenelubricants almost 2 years

    So for binary operators on booleans, Java has &, |, ^, && and ||.

    Let's summarize what they do briefly here:

    For &, the result value is true if both operand values are true; otherwise, the result is false.

    For |, the result value is false if both operand values are false; otherwise, the result is true.

    For ^, the result value is true if the operand values are different; otherwise, the result is false.

    The && operator is like & but evaluates its right-hand operand only if the value of its left-hand operand is true.

    The || operator is like |, but evaluates its right-hand operand only if the value of its left-hand operand is false.

    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 to E1 = (T)((E1) op (E2)), where T is the type of E1, except that E1 is evaluated only once.

    As proof, the following snippet throws a NullPointerException, not an ArrayIndexOutOfBoundsException.

        int[] a = null;
        int[] b = {};
        a[0] += b[-1];
    
  • EFraim
    EFraim over 14 years
    But then C/Java was never meant to be beautiful.
  • Yishai
    Yishai over 14 years
    Java supports <<=, >>= and >>>=, so that isn't strictly true.
  • zzawaideh
    zzawaideh over 14 years
    true. I didn't think of those. I guess the only explanation is then how frequently it is used.
  • polygenelubricants
    polygenelubricants about 14 years
    I 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
    polygenelubricants about 14 years
    I 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
    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
    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
    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
    p00ya about 14 years
    In 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
    polygenelubricants about 14 years
    I 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
    David Thornley about 14 years
    @PSpeed: In that case, a -= b; would work entirely differently from a &&= b;.
  • oHo
    oHo about 12 years
    Hi @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
    adventurerOK almost 12 years
    What 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
    oHo almost 12 years
    Hi @adventurerOK. Sorry I am not sure to understand what you mean... I think a&=b; is faster than if(a) a=b; when using values stored within the CPU registers. However, if b is in external memory (not cached), then if(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
    Tor Klingberg almost 11 years
    I 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
    oHo almost 11 years
    Thanks @TorKlingberg for your feedback. I am just realizing that people may think different! All right, I update my answer ;) Cheers
  • Radiodef
    Radiodef almost 9 years
    For that loop you probably just want to do if (fn(item)) { bVal = true; break; }.
  • Franz B.
    Franz B. almost 9 years
    I 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 line bool isOk = f1() || f2() || f3() || f4(); because that's what I was to blind to see myself.
  • oHo
    oHo almost 9 years
    Thanks @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
    fishinear about 7 years
    Your 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 than isOk &&= f1();
  • asgs
    asgs about 7 years
    I'd barely consider &&= to be ugly
  • UKMonkey
    UKMonkey about 5 years
    On 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
    v.oddou about 4 years
    before 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
    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.