19

Possible Duplicates:
Why doesn't Java have compound assignment versions of the conditional-and and conditional-or operators? (&&=, ||=)
Why does a “&&=” Operator not exist?

Today at work I wrote the following LOC (the real identities of b and b1 are confidential :)

b &&= b1; // meaning b = b && b1; 

I stared at it for a couple of seconds and realized that there exists no such operator. Just to be sure, I clicked on compile and it failed. To be dead sure I consulted the standard.

Are there specific reasons that there are no such operators? I can think of some:

  1. b &&= b1 and b = b && b1 may not be equivalent because of short-circuit evaluation of &&.
  2. &&= is ugly
  3. &&= is rarely needed

I do not claim that it would be very useful to have such operators, no. I also don't claim that any or all of the three above reasons are not enough to refrain from creating that operator. My question is the following: is there maybe a much more serious reason which I am overseeing?

Community
  • 1
  • 1
Armen Tsirunyan
  • 130,161
  • 59
  • 324
  • 434
  • Yes there is, you could have two "true" boolean values (both greater than one), where their bitwise-and value is "false"... Try bitwise and 2 and 1 and you get 0 (false), where a logical and would produce true – LorenVS Oct 18 '10 at 20:23
  • 2
    `b &= isSomethingWithSideEffects();` would run the function regardless. but if it was changed to `&&=` presumably it wouldn't in the case that b was false, no? – Dusty Oct 18 '10 at 20:26
  • 1
    Sorry, I don't understand why Dingo's comment has been upvoted. Could someone explain please? – John Oct 18 '10 at 20:33
  • @Victor someone posted a (now deleted) comment asking if there was a situation where `&=` would different from `&&=`. Your comment then said 'no there is not' which I (and I think several others) took as a reply to the comment above you, not the question as a whole. – Dusty Oct 18 '10 at 20:33
  • 2
    @John - it was a counter example to a now-deleted suggestion that `&=` was equivalent to `&&=` (as was my comment) – Dusty Oct 18 '10 at 20:35
  • OK, I see now. Thanks Dusty! – John Oct 18 '10 at 20:36
  • `uint8_t b = 1;` ... `uint32_t b1 = 0x1000;` ... `b &&= b1;` In this case you would expect `b` to be some true value, but if `&&=` were the same as `&=` this would be 0 (false) because of the truncation of upper bits. Since b1 may have been some error code returned from a function (ie, b1's meaning may extend beyond just being a boolean value) this could result in different results. Another equivalent example would be `uint8_t b = 1;` ... `void * b1 = malloc(99);` ... `b &&= b1;` – nategoose Oct 18 '10 at 20:36
  • 1
    Forget the question - I'm dying to know what untold power the secrets of the real identities of `b` and `b1` would give me! – Michael Burr Oct 18 '10 at 21:19
  • 1
    @Michael: Only the chosen ones shall know – Armen Tsirunyan Oct 18 '10 at 21:23
  • 2
    @Close-Voters: Please consider not closing this question inasmuch as the potential duplicates both refer to Java and the answer is there is no &&= in Java because there is none in C. None of the threads provides a satisfactory answer which I am hoping to get here. Just consider it. Thank you. – Armen Tsirunyan Oct 19 '10 at 11:12
  • @Armen: Just because those questions are tagged [java] doesn't mean they're completely restricted to Java. Both accepted answers mention C, for example. Do we really want to cover the exact same ground in a new question for every language when the only difference is s/$language_a/$language_b/g? For that matter, why restrict your question to C#/C++/C? Couldn't we just add a [java] tag here? Please consider a bounty on the other questions if you want to inspire additional answers. –  Oct 20 '10 at 14:16
  • FWIW, if (!b) b = b1; isn't so bad for what you wanted to do. –  Oct 20 '10 at 14:25

6 Answers6

16

I don't know why both the question and some of the answers mention short-circuiting behavior of the corresponding logical operators as a potential issue.

There's absolutely no short-circuit-related problems with defining &&= and ||= operators. They should be defined uniformly with += and other similar operators, meaning that a &&= b should be equivalent to a = a && b, but with a being evaluated only once in &&= version. This means in turn that b is not evaluated at all if a is originally zero. Easy.

So, the only reason they don't exist in the language is, well, "just because".

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
  • 3
    Exactly. Perl has these operators, with that behaviour; and while I've heard many criticisms of Perl, I've never heard anyone complain that `&&=` is confusing. – Porculus Oct 18 '10 at 21:33
  • Good point about the short-circuit thing, but technically speaking a = a + b is not equivalent to a += b if a has side effects, e.g. is a function printing something and returning a reference(in the first case will print twice and in the second only once). – Armen Tsirunyan Oct 18 '10 at 21:35
  • @Armen Tsirunyan: Well, I wasn't trying to make it formally prefect. The language standard defines `a += b` as equivalent to `a = a + b` except that in `+=` version `a` is evaluated only once. The same way the `&&=` can be defined. – AnT stands with Russia Oct 18 '10 at 21:43
  • I don't understand. 'a = a && b' is equivalent to "if a is true, evaluate b and make a true if b is true and false otherwise". You'd really **like** an asignment statement that may or may not bother to actually evaluate the entire RHS? May or may not actually perform an assignment? I think that would confuse the heck out of quite a lot of people. Of course much else in C already does that, so I guess why not... – T.E.D. Oct 18 '10 at 22:33
  • 3
    @T.E.D.: Yes, I would really like such an operator. The `&&` and `||` operators already have significantly different behavior from other binary operators (like `+`, for example), and we have been living with that just fine. I don't see any problem with `&&=` and `||=` also having significantly different behavior compared to other forms of assignment, even if it involves optional evaluation of the RHS. – AnT stands with Russia Oct 18 '10 at 23:14
  • @T.E.D. Using the same logic... "Who would want `+=` ? An assignment operator that (except for trivial cases) doesn't actually assign the right hand value to the left hand object?". None of these operations make sense if you ignore the operator. – MSalters Oct 19 '10 at 08:50
  • I think they are pretty different issues. No matter what happens with operators like `+=`, you can count on the RHS at least getting evaluated. With something like `&&=` that is not the case. Pretend the RHS includes a function call (which would or would not get actually called depending on the value of the LHS) and perhaps you will see the issue. – T.E.D. Oct 19 '10 at 13:01
  • @T.E.D.: Yes, but that's the difference that's already there with `&&` operator. For example, with `+` operator you can count on both sides getting evaluated. With `&&` you can't. – AnT stands with Russia Oct 19 '10 at 14:25
  • 1
    @T.E.D.: In `a && b;` b isn't evaluated too. – user unknown Jul 13 '11 at 13:01
  • @Armen Tsirunyan: Can you show an example, where `a` in `a = a && b;` has sideeffects, and is assignable; can be a LHS? I fear I can't follow that argument. – user unknown Jul 13 '11 at 13:04
  • @user unknown: `bool& f() {static bool b = true; cout << "Hello"; return b; }`. Now you can write `f() = f() && false;` which will print `Hello` twice. But if `f() && = false` were possible, you'd get only one `"Hello"` – Armen Tsirunyan Jul 13 '11 at 13:06
  • Well, I'm sorry to disturb from a c++ - beginners perspective, but the assignment in `f() = f() && false;` - does it have any effect? Why would you write something like that, and not `f (), f () && false;` It would be possible to write such a statement, but has the assignment any meaning in such a statement? – user unknown Jul 13 '11 at 14:34
9

I've wanted them before as well. I doubt that ugliness was by itself the determining factor, the short-circuiting behavior is the best argument against them I've heard so far.

Another contributing factor is that C is designed to operate close to the metal, pretty much all of the operators correspond directly to an instruction in major architectures. I don't think there is an instruction on x86, PPC, etc that directly implements b &&= b1;

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • 1
    +1. What operations were available on the PDP-11 is probably more of a deteriminant, but I still think you are onto something there. – T.E.D. Oct 18 '10 at 22:27
  • @T.E.D.: Of course, but modern major architectures inherit the bulk of their instructions from the architectures of yore. Especially on the common areas. – Ben Voigt Oct 18 '10 at 23:48
  • 1
    Huh? Short circuiting is the argument *for* them. Without that, just use `&=` with Boolean values. As for instructions, the same ones are used as for `b && ( b = b1 );`, (but with only one evaluation of `b` of course). The compiler chooses between a branch and a bitwise AND. – Potatoswatter Oct 19 '10 at 00:20
  • @Potatoswatter: The argument against is that they'd be the only assignment operators to short-circuit. And your little snippet doesn't have the required behavior, it needs to be `if (b) b = (b1 != 0);`. Your version, unlike operator `&&` could result in values other than 0 or 1. – Ben Voigt Oct 19 '10 at 00:41
  • @Potatoswatter: Most (all?) of the other compound assignment operators actually use *fewer* instructions than would be needed to save the operator result into a temporary location. e.g. `c = a + b;` becomes (MOV C, A; ADD C, B) and `a += b;` becomes (ADD A, B). The logic for `&&=` is a lot more complex. – Ben Voigt Oct 19 '10 at 00:45
  • @Ben: I'm just trying to illustrate how the compiler would do the short-circuiting. `b && ( b = (bool) b1 )` would seem to be equivalent to the required behavior, but that's besides the point. They would be the only assignment operators to short-circuit… corresponding to the only non-assignment binary operators to short-circuit. – Potatoswatter Oct 19 '10 at 00:55
  • @Ben: If `b` converts to `true`, then no assignment is necessary, so it's just a branch. Otherwise, `b` gets assigned. The logic is no more complex than for the `&&` and `=` operators used separately… not that instruction counts on favorite architectures have any relevance. – Potatoswatter Oct 19 '10 at 00:57
  • … well, if `b` is not type `bool`, then the assignment is necessary. But the compiler can be smart about that, just as it's smart about deciding not to really short circuit if there are no side effects. – Potatoswatter Oct 19 '10 at 00:59
  • @Potatoswatter: If `b` is false, then `&&` short-circuits and neither assignment nor even evaluation of `b1` is needed. When `b` is true is exactly when assignment might be necessary. – Ben Voigt Oct 19 '10 at 01:11
  • @Ben: Right. I got that backwards. Anyway it doesn't change anything. – Potatoswatter Oct 19 '10 at 01:17
  • Actually Ben, I think the DEC chips C was built around inspired modern architectures mostly as a counter-example. They tried to make all common software operations instructions, to the extreme that they ended up having CPU instructions for list manipulations. Some designers thought this was exactly the **wrong** approach, and invented RISC. – T.E.D. Oct 19 '10 at 13:07
  • @T.E.D.: So you're saying that newer chips kept only the instructions that C compilers tended to use, and dropped support for more lispy instructions? That makes sense too. – Ben Voigt Oct 19 '10 at 13:53
  • @Ben Voigt - It's more like newer chips (note: the 8086 instruction set is not "new"). Decided that rather than try to make complex instructions to help assembly programmers, they should make very simple instructions to help themselves speed things up. Since almost everyone uses compilers now, only the compiler writers have to deal with the pain of doing real work with a very simple instruction set. Its a totally different way of looking at instruction set design. See http://en.wikipedia.org/wiki/Reduced_instruction_set_computing for more information. – T.E.D. Oct 19 '10 at 15:07
2

The biggest reason the operators don't exist is probably that K&R didn't think of any appealing way to define them. I've also sometimes wanted a ->= operator (ptr->=next would be equivalent to ptr = ptr->whatever).

A problem I think with &&= is that it's not obvious which of the following would be most useful, or which it's supposed to be:

  if (lhs && rhs) lhs = 1; else lhs = 0;
  if (!rhs) lhs = 0; else lhs = !(!lhs));
  if (lhs && !rhs) lhs = 0;
  if (!rhs) lhs = 0;
The first variation is the one most clearly suggested by the syntax, but from a practical standpoint, if neither term is zero, it would often be more useful to leave the left-hand side alone than to set it to "1".

BTW, I've often wished for a variation of the comma operator which would evaluate the left side, save the value, then evaluate the right side, and return the value of the left side. Equivalent to:

int foo(int p1, int p2) return p1;
except applicable to any type (p2 need not be the same type as p1, and could be void), and with a guaranteed left-to-right evaluation order. Would be very handy for things like post-increment indexing with a non-unit step, e.g., arr[ptr ~, ptr+=2]; or for certain types of data-swap operations, e.g., var1 = (var2 ~, var2=var1); etc.
supercat
  • 77,689
  • 9
  • 166
  • 211
  • 4
    In C, all the compound assignment operators (`op=`) are defined as `lhs = lhs op rhs` with the `lhs` expression being evaluated only once. So I think there's little ambiguity as to how it `&&=` would be defined (the same way). – Michael Burr Oct 18 '10 at 21:27
  • @Michael Burr: That would be sytactically the natural implementation, but in practice there are times the third would be more useful than the first, but I can't think of as many where the first would actually be more useful. – supercat Oct 18 '10 at 23:07
  • 1
    I had proposed this equivalent to a now-deleted question: `if (lhs) lhs = (rhs != 0);` Seems to have the expected short-circuiting behavior. However, it's probably faster to perform `if (lhs) lhs = rhs;` which also short circuits but doesn't coerce all non-zero rhs to 1. – Ben Voigt Oct 18 '10 at 23:53
2

Because the result of a && b is always 0 or 1, I think the interpretation of this would only be unambiguous for the C99 _Bool type. Since this didn't exist at the time C was created, this operator was then not included. And nowadays nobody easily adds another operator to C, since this would have an impact on all existing parsers.

Jens Gustedt
  • 76,821
  • 6
  • 102
  • 177
1

Personally I'd vote for the first rationale you went with. The boolean operators have short-circuit semantics, which would make for some really gnarly situations if translated into asignment operators. Either you don't make them short-circuit anymore, or you created some weird "optional" assignment operator (do the stuff on the right and assign in the result only if the value on the LHS is already non-zero). Either way you'd create subtle bugs because people would be expecting the other behavior.

T.E.D.
  • 44,016
  • 10
  • 73
  • 134
0

EDIT: Wrong language, but still applies

I agree with your three reasons, although there is one scenario where I have lamented the lack of this operator, when writing custom deserialization routines. In a couple of cases where an improperly serialized object wasn't really "exceptional" (and to prevent exception overhead in C# for very common failures), I would use boolean return values to signify whether a deserialization operation was successfull.

This code is completely theoretical, and Nested1, Nested2 and Nested3 are all structs:

public struct ComplexStruct
{
    private Nested1 nested1;
    private Nested2 nested2;
    private Nested3[] nested3;

    public bool Read(Reader reader)
    {
       bool ret = true;
       int nested3Length = 0;

       ret &&= nested1.Read(reader);
       ret &&= nested2.Read(reader);
       ret &&= reader.ReadInt32(ref nested3Length);

       for(int i = 0; (ret && i < nested3Length); i++)
       {
          ret &&= nested3[i].Read(reader);
       }

       return ret;
    }
}
LorenVS
  • 12,597
  • 10
  • 47
  • 54
  • Well, that was almost the same scenario when I needed it (the loop part). I will now edit my question to clarify that – Armen Tsirunyan Oct 18 '10 at 20:26
  • In that case, you could just `return false;` early. – Ben Voigt Oct 18 '10 at 20:28
  • Cool... In my case, I wanted the short-circuiting behavior, so I ended up using ret = ret && xxx for most of my cases... It's a little verbose, but at least it makes it clear that I'm doing short-circuiting boolean comparisons – LorenVS Oct 18 '10 at 20:46