27

Can anyone explain me how different spacing affects the unary operator?

int i = 1;
int j = i+ + +i; // this will print j=2
int k = i++ +i; // this will print k=3
int l = i+++i; // this will print l=3
int m = i++++i; // compile time error

.

hello_there_andy
  • 2,039
  • 2
  • 21
  • 51
Ravi Godara
  • 497
  • 6
  • 20
  • 4
    just for curiosity, if you are executing all these statements in a sequence, then for int l = i+++i;, the initial value of i would be 2 because it has already been incremented in the previous step, so it might affect the result as well. – Sahil Mahajan Mj Feb 25 '14 at 11:52

2 Answers2

43

First, let's separate this into three separate cases which can't interact:

int i = 1;
System.out.println(i+ + +i); // 2

int j = 1;
System.out.println(j++ +j); // 3

int k = 1;
System.out.println(k+++k); // 3

Now let's rewrite them using brackets:

int i = 1;
System.out.println(i + (+(+i)));

int j = 1;
System.out.println((j++) + j);

int k = 1;
System.out.println((k++) + k);

First operation

Here we can't be using the prefix or postfix ++ operators, as we don't have a token of ++ anywhere. Instead, we have a binary + operator and two unary + operators.

Second operation

This one's simple: it's pretty much as it reads, a postfix ++ operator followed by a binary + operator (not the unary + operator that +j might otherwise imply).

Third operation

The final line is parsed as (k++) + k rather than k + (++k). Both will actually give the same answer in this situation, but we can prove which is which by using two different variables instead:

int k1 = 1;
int k2 = 1;
System.out.println(k1+++k2); // Prints 2
System.out.println(k1); // Prints 2
System.out.println(k2); // Prints 1

As you can see, it's k1 that's been incremented rather than k2.

The reason that k+++k is parsed as tokens of k, ++, +, k is due to section 3.2 of the JLS, which includes:

The longest possible translation is used at each step, even if the result does not ultimately make a correct program while another lexical translation would.

Fourth operation (compile failure)

The same "longest possible translation" rule parses i++++i as i, ++ ,++, i which isn't a valid expression (because the result of the ++ operation is a value, not a variable).

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 4
    I am not certain that operator precedence is the reason behind the interpretation of the third line. I suspect that it is a consequence of the maximal munch rule implemented in the lexer: when it sees a sequence of characters, it tries to construct the longest token that it can. In case of a sequence of plus signs that would be a `++` token. – Sergey Kalinichenko Feb 25 '14 at 09:54
  • @dasblinkenlight: Hmm. You could be right. I think I'll change it to just say what I definitely know (the actual interpretation) rather than the explanation :) – Jon Skeet Feb 25 '14 at 09:55
  • @JonSkeet, Is the third operation `(k++) + k` is because of _operator precedence_ or because of _maximum munch rule_ ? – Zeeshan Feb 25 '14 at 11:05
  • @Zeeshan: I haven't been able to work that out for sure. Looks like I accidentally left a reference to precedence in there. I'll remove that now. – Jon Skeet Feb 25 '14 at 11:06
  • @Zeeshan `k+++k` was parsed as `k++ + k` because of maximum munch rule. But the expression `k++ + k` (but it doesn't say itself which operator evaluate first) is equivalent to `(k++) + k` because of precedence rules. – Grijesh Chauhan Feb 25 '14 at 12:26
  • @GrijeshChauhan: Operands are *always* evaluated left-to-right. That's not a matter of precedence. It's not clear where you believe the precedence part comes in, bearing in mind the maximum munch rule (which I still haven't found a reference for in the JLS, unfortunately) splits it into `k++ + k`. There's no room for precedence to change what that means - there's a unary postfix-++ opreator and a binary + operator... there's no grouping which precedence could affect, as far as I ca ntell. – Jon Skeet Feb 25 '14 at 12:30
  • @JonSkeet, [Lexical Translations](http://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.2) – Zeeshan Feb 25 '14 at 13:03
  • Note that the maximum munch rule also causes the fourth line to fail to parse. It is interpreted as the sequence of tokens: i, ++, ++, i, which is not a valid expression. – fishinear Feb 25 '14 at 14:09
  • @JonSkeet, is the outcome the same in C#? – Ian Ringrose Feb 25 '14 at 15:17
  • @Ian: I haven't checked, but I expect so. – Jon Skeet Feb 25 '14 at 15:25
13

+ is an operator, and ++ is an operator, but + + is not - + + is interpreted as two +s, not one ++. So the space forces your code to be interpreted differently.

+ is both a binary operator which adds two numbers and a unary operator which does not change a number (it exists only for consistency with the unary - operator).

If we use add instead of binary +, no-change instead of unary +, and increment instead of ++ then it might be more clear.

int j=i+ + +i becomes int j = i add no-change no-change i;.
int k=i++ +i; becomes int k=i increment add i;.
I suspect int k = i+++i; also becomes int k = i increment add i; but I have not checked this with the language specification.

user253751
  • 57,427
  • 7
  • 48
  • 90
  • 8
    Importantly, `+ +` is interpreted as a binary `+` operator followed by a unary `+` operator (I believe). That makes your "add add add" interpretation less helpful than "add unary-plus unary-plus". So `int j = i+ + +i` is equivalent to `int j = i + (+(+i)); – Jon Skeet Feb 25 '14 at 09:37
  • 1
    More importantly, please explain what's the deal with three pluses in a row. – Sergey Kalinichenko Feb 25 '14 at 09:42
  • 2
    @dasblinkenlight Just got confused by writing confusing code. Studying bizarre edge cases can be useful to get an understanding of how things really work. ;) – Peter Lawrey Feb 25 '14 at 09:44