Increment in function overwritten by +=
Asked Answered
L

2

17

A method called in a ternary operator increments a variable and returns a boolean value. When the function returns false the value is reverted. I expected the variable to be 1 but am getting 0 instead. Why?

public class Main {
    public int a=0;//variable whose value is to be increased in function
    boolean function(){
        a++;
        return false;
    }
    public static void main(String argv[]){
        Main m=new Main();
        m.a+=(m.function()?1:0);
        System.out.println(m.a);//expected output to be 1 but got a 0 !!!!!
    }
}
Lowson answered 21/5, 2016 at 4:33 Comment(17)
Isn't this supposed to be undefined behavior?Handspring
Undefined behavior is a C/C++ concept.Kleiman
dont you think the return type of function must be intWorkout
The expected output should be 0. m.function() always returns false, so the value that gets added on is 0... 0 + 0 = 0.Brutal
@LukePark but the function increments aHandspring
@holidayCoder No.Kleiman
@PatrickRoberts But it doesn't matter that it does. m.a = m.a + 1 or 0 depending on whether function is true.Brutal
function is returning false which means it is 0 and in operation it is false so m.function()?1:0 also return 0??Workout
@holidayCoder false != 0 in Java... Ternary Operator is (condition ? valueIfTrue : valueIfFalse).Brutal
@LukePark ignoring the information revealed in the answer below, what this looks like it expands to is: a += (a++ == 1) ? 1 : 0; (I know that the function always returns false but this was the only inline statement I could think of as equivalent in this situation.Handspring
@PatrickRoberts It looks like it does but it doesn't.Brutal
@LukePark your initial statement is still incorrect though and that is what I am pointing out. The return value of the function and the ternary operator alone have nothing to do with the end value of m.a. It's the fact that the += operator somehow replaces the post-increment state of a.Handspring
@PatrickRoberts My initial statement isn't wrong. I think you are misunderstanding the order. Replacing values, it's pretty much saying m.a = 0 (the current value) + (potentially 1 or 0).Brutal
@LukePark my apologies. I misinterpreted your initial claim to ignore the fact that the function incremented a.Handspring
@PatrickRoberts No worries!Brutal
What happens if you call instead a += function()?1:0;? The same thing? I don't have a way to compile C# currently.Kiblah
@PatrickRoberts: Even in C or C++ the equivalent program would not have undefined behaviour. There are sequence points enough to ensure that a well-defined order is imposed.Howlett
C
23

Basically m.a += (m.function() ? 1 : 0) compiles into

 int t = m.a; // t=0 (bytecode GETFIELD)
 int r = m.function() ? 1  : 0; // r = 0 (INVOKEVIRTURAL and, IIRC, do a conditional jump)
 int f = t + r; // f = 0 (IADD)
 m.a = f // whatever m.a was before, now it is 0 (PUTFIELD)

The above behavior is all specified in JLS 15.26.2 (JAVA SE 8 edition)

Contessacontest answered 21/5, 2016 at 4:54 Comment(1)
Upvoted +1 for you, but -1 for the JLS being foul in this respect.Purgatory
C
19

You have two operations operating on m.a in one call; in main

m.a += (m.function()?1:0);

pushes the value of a on the frame, and then invokes m.function() (which returns false), thus the ternary expands to m.a += 0; (and the value of m.a from the frame is added to 0 and stored in m.a). Thus the value is incremented in m.function() (and then reset in main). Consider it this way,

m.a = m.a + (m.function() ? 1 : 0);

The value of m.a is determined before the evaluation of m.function() (thus it is a post increment operation). For the result you expected, you could do

m.a = (m.function() ? 1 : 0) + m.a;
Cosgrave answered 21/5, 2016 at 4:44 Comment(7)
Why is it evaluated this way? Can you cite the JLS sources that cover this?Kleiman
So the behavior is related to stack calls?Handspring
function is returning false which means it is 0 and in operation it is false so m.function()?1:0 also return 0??Workout
I was perhaps unclear, it is really unrelated to the ternary, it is because of the post increment operator being used.Cosgrave
A prior user answered this with the same information in less detail and people voted him down twice... If he is still here, kudos to you, I always agreed with you.Brutal
docs.oracle.com/javase/specs/jls/se8/html/… explains how compound assignments are evaluated @JohnKugelman.Appressed
@holidayCode : yes - m.function() ? 1 : 0 will always return 0 because m.function() will always return false. The entire question is "why is the a++ in function() ignored?". The answer is that the in main() the value of a is pushed onto the stack before function() is called, so the modification to a is not noticed. IMO this is a compiler bug - the compiler should have recognized that a call to a class function could potentially modify a class variable and thus shouldn't have pushed a until after function was completed.Knockknee

© 2022 - 2024 — McMap. All rights reserved.