Ternary operator, syntax error when using assignment - java

The following 3 lines of code below compile OK. (Please note that this code is an example of "artificial Java coding", and consequently wouldn't be seen in professionally written code.)
int x, y;
boolean b=true;
x = b ? y=1 : 2; // Compiles OK.
If I now change the code in line #3 above, so that it looks like the following code line below, the compiler generates an error.
// Change the position of the "y assignment", and now the code doesn't compile.
x = b ? 1 : y=2;
Here is the syntax error message:
Can someone please explain this behaviour (to a rookie Java learner)? Thank you.

Short:
This is because of operator precedence. The first case is equal to this:
x = (b ? (y=1) : 2); // Compiles OK.
While the second is:
x = (b ? 1 : y) = 2;
The first one compiles indeed fine, because an assignment gets evaluated to the new value. So, if b is true, it will cause to be both x and y equal to 1. The second one is like saying: x = 1 = 2. So, yes, to fix this compiler error, add paratheses to your statement:
x = (b ? 1 : (y = 2)); // Outer () are not needed, but is clearer, IMHO.
Longer:
First of all, operator precedence in Java says that the assignment operators have lower priority than the conditional ternary operator. This means that your second expression is equivalent to:
x = (b ? 1 : y) = 2;
As you can see, this looks plain wrong. Indeed, JLS §15.26 says this:
There are 12 assignment operators; all are syntactically right-associative (they group right-to-left). Thus, a=b=c means a=(b=c), which assigns the value of c to b and then assigns the value of b to a.
The result of the first operand of an assignment operator must be a variable, or a compile-time error occurs. (This explains the compile time error you face)
At run time, the result of the assignment expression is the value of the variable after the assignment has occurred. The result of an assignment expression is not itself a variable.
Applying right-associativity:
x = ((b ? 1 : y) = 2);
Finally we can see why this generates a compiler error: the result of a ternary conditional operator is not a variable (which is actually not in the JLS as far as I can find, however the compiler tells you in a simple test case like this one: https://ideone.com/kMr7Xv).

See "Java operator precedence".
Meanwhile, use:
x = (b ? 1 : (y=2));

Java operator precedence is as follows
http://docs.oracle.com/javase/tutorial/java/nutsandbolts/operators.html
here ternary comes before assignment operation. so your statement will be like this
x= ( ternary evaluation )= assignment value
if you still want set value for y , when b is false, you may use () for 'y=2' bring inside ternary evaluation.
x = b ? 1 : (y=2);

Brother, try putting expressions in brackets.
X= (b? 1 : (y=2));
this will work fine.

Related

how this Ternary Operator work with this statemnt?

i just generate this methode to find max val in some matrix and somehowe i was able to change int val insdie Ternary Operator (java 8)
int max=0, indexToReturn=0;
int size= arr[0].length;
for (int i=1 ; i < size ; i++)
{
//
// ¯\_(ツ)_/¯
max = (!(arr[j][indexToReturn] > arr[j][i])) ? indexToReturn= i : arr[j][indexToReturn] ;
}
return max > 0 || indexToReturn==size-1 ? arr[j][indexToReturn] : null;
(the method compile and working)
im not realy sure evan how its compile from what i saw online Ternary Operator syntax :
variable = Expression1 ? Expression2: Expression3
can someone explain me what im missing here ?
The reason this works is because an assignment is an expression. The value of an assignment is the value assigned. This sounds theoretical, so let us look at an example:
int i, k;
i = (k = 5);
System.out.println(i);
System.out.println(k);
Ideone demo
The value of the expression k = 5 is the assigned value 5. This value is then assigned to i.
Armed with this knowledge, we see that indexToReturn= i is an expression that evaluates to the value of i. When we swap Expression2 and Expression3, the ternary operator breaks because the = i is not evaluated as part of the ternary operator (due to operator precedence). If we set parentheses around Expression2, it works as expected.
I would discourage using the fact that an assignment is an expression. (Ab)using this fact often leads to hard-to-understand code.

conditional expression "? :" compiles despite branches returning different types

I've started to learn java and I'm confrunting with the following conditional expression:
((1<2)?5:(3<4))
In the book where I've found this example it says that it's a syntax error because it can't convert a numerical value to a boolean one.
Same pages after, there is a test with different exercises, including this one.After writing and compiling in eclipse it gives me the output 5.
Why? I've read some things about this operator and it clearly says that the both of the expressions must be booleans or arithmetics, so it's a problem with eclipse?
when they talked of compiler error case that would be something like this
int a= ((1<2)?5:(3<4));
but as (3<4) returns boolean it cant be assigned to integer variable
but when you simply do System.out.println(((1<2)?5:(3<4))); it doesn't have to assign the value to any variable,and it prints the output value using the method System.out.println(Object)
if you would change the expression a bit and do :- System.out.println(((1>2)?5:(3<4))) then it would print true as output
The conditional operator has three operands - the first is the condition, and the second and third are separate "branches" as it were. Which branch is evaluated depends on whether the condition evaluates to true or false.
In your case, you have:
Condition: 1 < 2
Branch1: 5
Branch2: 3 < 4
Now the problem is that the two branches are of different types here, so there's no useful primitive result type of the expression. It's (surprisingly, IMO) valid, with an overall expression type of Object - basically, both branches involve boxing. So this:
Object o = 1 < 2 ? 5 : 3 < 4;
is equivalent to:
Object o = 1 < 2 ? (Integer) 5 : (Boolean) (3 < 4);
That's specified in JLS 15.25 - your situation is shown in "Table 15.25-B. Conditional expression type (Primitive 3rd operand, Part II)" which shows that when the third operand has a type of boolean and the second has a type of int, the result is lub(Integer,Boolean) - basically Object.
Now this would be fine:
int x = 1 < 2 ? 5 : 4; // Both branches are of type int
And so would this:
// Very confusing with all these conditions, but valid!
boolean y = 1 < 2 ? 5 < 6 : 3 < 4; // Both branches are of type boolean
... but your current situation has one branch of type int, and one of type boolean.
The only "problem" with this ternary operator is that it return different types.
Let's unwrap it with if conditions in pseudo-code:
((1<2)?5:(3<4))
if (1 < 2) {
// returns int
return 5;
}
else {
// either returns boolean (true)
if (3 < 4) {
return true;
}
else {
return false;
}
}
So the expression can be valid in certain conditions.
For instance, Object o = ((1<2)?5:(3<4)); will compile fine (with warnings on the 3 < 4 part), because an Object can be boxed from both primitives boolean and int.
If you pass it to System.out.println() it will not complain because all values are converted to String.
So,
System.out.println((1<2) ? 5 : (3<4));
//Will print 5
System.out.println((3<2) ? 5 : (3<4));
//Will print true
But,
int i = ((3<2) ? 5 : (3<4));
or
boolean b = ((3<2) ? 5 : (3<4));
will result in a compilation error.
Since in an a?b:c expression, the types of b and c can be different, the Java compiler has to try to infer the return type of the expression, to find a type that fits both operands.
This is done by looking at the type tree and finding the closest common ancestor. For reference types, this closest common ancestor is Object in a worst case scenario. (1 > 2) ? new StringBuilder() : new ArrayList(); will have a return type Object, so if you want to assign it to a variable of type Object (or pass it to a method that expects a parameter of Object type), it's fine. Otherwise you'll get a compile error because there's no guarantee that the result can be cast to any other type.
Where your scenario is slightly more complicated is that it features primitives as b and c: an int and boolean. These will have to be auto-boxed to Integer and Boolean first, then the process above runs as normal, the return type is Object. But if you want to assign an Object to an int, that won't work, hence why int x = ((1<2)?5:(3<4)); will fail to compile but Object x = ((1<2)?5:(3<4)); will be valid.
Note: in practice it's slightly even more complicated by the fact that there could be multiple, unrelated common ancestors, but that doesn't change the basic principle.
The statement by itself will not give any compilation error but the result of the conditional statement cannot be assigned to a variable because if the condition is true(as in the current case) the result will be 5 which is an Integer but if the condition is false then the result will be true which is a Boolean.
So to get the compilation error do the below,
Integer a = ((1>2)?5:(3<4));
or
Boolean a = ((1>2)?5:(3<4));
Just for the sake of making the code to compile we can assign the result to a base class.
Serializable a = ((1>2)?5:(3<4));
or
Object a = ((1>2)?5:(3<4));
The following compiles and runs correctly, no matter what the values of x and y are. You get either the number 5 or the boolean true. There's no problem since the result isn't assigned anywhere (or rather the result is an Object passed to println(Object o)).
int x = 1;
int y = 2;
System.out.println(x<y ? 5 : 3<4);
The problem comes with assignments.
int x = 1;
int y = 2;
int a = x<y ? 5 : 3<4; // Won't compile without a cast to int, if x > y, results in a `ClassCastException`.
So while it's possible to have different types as the result, it's not necessarily a good idea. They both need to be assignable to the result, so the following will always work, no matter what is returned from either statement.
Object o = x < y ? "String object" : new ArrayList(); // Works since the return type is compatible
? is a ternary operator as detailed in JSL (§15.25):
variable = condition ? value if true : value if false;
Example
String isFalse = 3 < 4 ? "true" : "false"; // false
String isTrue = 3 == 3 ? "true" : "false"; // true
The type of a conditional expression is determined as follows:
If the second and third operands have the same type (which may be the null type), then that is the type of the conditional expression.
If one of the second and third operands is of primitive type T, and the type of the other is the result of applying boxing conversion (§5.1.7) to T, then the type of the conditional expression is T.
If one of the second and third operands is of the null type and the type of the other is a reference type, then the type of the conditional expression is that reference type.
Otherwise, if the second and third operands have types that are convertible (§5.1.8) to numeric types, then there are several cases:
Now, knowing this and translating your expression:
((1<2)?5:(3<4))
You get 1<2=false and 3<4=false
false ? 5 : false
So if you try to assign a variable
boolean var = false ? 5 : false
int var = false ? 5 : false
You will have the syntax error because it can't convert a numerical value to a boolean one:
Type mismatch: cannot convert from Object&Comparable<?>&Serializable to int<br>
↑ (3<4) ↑ variable assigned
3<4 will return boolean. Not int.
1<2 ? yes, then print 5
But if you will change "<" to ">" you will get "true".

Logic statement not returning a variable, rather a value

(Math.random() > 0.75) ? type = TreeType.BIG_TREE : type = TreeType.TREE
How come (Math.random() > 0.75) returns a value, according to console, rather than a variable? The above statement is part of an if-else ladder.
You want the following
type = (Math.random() > 0.75) ? TreeType.BIG_TREE : TreeType.TREE
Good question. Actually what you have could hypothetically work if you make it a full statement. e.g.
TreeType tree =
(Math.random() > 0.75) ? (type = TreeType.BIG_TREE) :
(type = TreeType.TREE);
compiles fine (assuming you're assigning type to something of type TreeType, of course). Notice that all I did was add TreeType tree = (and add parenthesis to deal with the order of operations). This is because assignments actually return a value, specifically whatever the right-hand side evaluated to.
Obviously,
type = (Math.random() > 0.75) ? TreeType.BIG_TREE : TreeType.TREE
would be preferred as it is more terse and readable.
According to: http://java.about.com/od/t/g/ternaryoperator.htm
The first operand is a boolean expression; if the expression is true then the value of the second operand is returned otherwise the value of the third operand is returned.
I believe what you are seeing is that the value of type after the assignment is complete is returned. (I haven't done java in a while, but that's likely the case.) You should instead do:
type = (Math.random() > 0.75) ? TreeType.BIG_TREE : TreeType.TREE;

Multiple statements if condition is true in shorthand if

I recently discovered the shorthand if statement and after searching online I couldn't find a definite answer.
Is it possible to execute 2 statements if the condition is true/false?
int x = (expression) ? 1 : 2;
for example
int x = (expression) ? 1 AND 2 : 3;
Seeing as i haven't comne across a example where they used it I guess it's not possible but I wouldn't want to miss out.
You're talking about conditional assignment. You should look at what is defined by what you've written:
int x = (expression) ? 1 AND 2 : 3;
That is evaluating 'expression' and if true executing '1 AND 2' then assigning the value to x. If 'expression' evaluated to false, '3' is evaluated and assigned to x. Hence you could definitely do something like this:
int x = (expression) ? GetInt1() + GetInt2() : 345;
What is important is that what you have found is not just a shorthand if. It is conditional assignment.
You can't have a statement return two values and that's all that ternary does. It is not a shorthanded if it is a method persay that returns values

What is the difference between '==' and '='?

I know that one of them is bitwise and the other is logical but I can not figure this out:
Scanner sc = new Scanner(System.in);
System.out.println("Enter ur integer");
int x=sc.nextInt();
if(x=0)//Error...it can not be converted from int to boolean
System.out.println("...");
The error means that x cannot be converted to boolean or the result of x=0 can not be converted to boolean.
== checks for equality.
= is assignment.
What you're doing is:
if( x = Blah ) - in Java this statement is illegal as you can not test the state of an assignment statement. Specifically, Java does not treat assignment as a boolean operation, which is required in an if statement. This is in contrast with C/C++, which DOES allow you to treat assignment as a boolean operation, and can be the result of many hair-pulling bugs.
When you write 'x = 0' you are saying "Store 0 in the variable x". The return value on the whole expression is '0' (it's like this so you can say silly things like x = y = 0).
When you write 'x == 0' it says "Does x equal 0?". The return value on this expression is going to be either 'true' or 'false'.
In Java, you can't just say if(0) because if expects a true/false answer. So putting if(x = 0) is not correct, but if(x == 0) is fine.
== is a comparison operator, and = is assignment.
== is an equality check. if (x == 0) // if x equals 0
= is an assignment. x = 0; // the value of x is now 0
I know the question has been answered, but this still comes up from time to time not as a programmer error but as a typographical error (i.e., the programmer knew what he meant, but failed). It can be hard to see, since the two look so similar.
I've found that a way to help avoid doing this is to put the constant expression on the left-hand-side, like so:
if (0 == x)
...
That way, if I accidentally use only one "=" sign, the compiler will fail with an error about assigning to a constant expression, whether or not the assignment operator is left-associative and whether the if conditional expects a strongly-typed Boolean.
if(x=0)
Here you're assigning the value of 0 to the variable x. The if statement in Java can't evaluate an integer argument as it can in many other languages. In Java, if requires a boolean. Try
if(x == 0)
to do a comparison.
Interpret the error to mean
"The expression
x=0
cannot be converted to Boolean."
Just to clarify about C/C++ - assignment is evaluated to the right operand
if(a = n)
is evaluated to n, so (n = 1) is true (n = 0) is false
One interesting note: Since assignment operator evaluates to the right operand, the following is valid in Java(albeit not pretty):
if (( x = blah ) > 0) ...
Parenthesis are needed because of operator precedence ( '>' binds stronger than '=').
As others have already said, '=' is assignment; '==' is compare.
in your program change
if(x=0)
to
if(x==0)
"==" checks for equality
"=" Is used for assignment.
It is giving you error cause you're assigning value to x in if(), where you're supposed to check for the equality. Try changing it to equality instead of assignment operator.
As others stated, = assigns while == compares.
However, these statements have their own values as well.
The = operator returns the value of its right-hand operand. This is how statements like a = b = c = 5 work: they are parsed as a = (b = (c = 5)), which evaluates to a = (b = 5) and then a = 5.
The == operator returns a boolean that is true if its operands are equal. The if statement runs its body if its argument is true. Thus, if headers like if (5 == 5) translate to if (true). This is why sometimes you see infinite while loops with header while (true); the while loop runs "while" toe argument is true.
If you had a boolean in your if statement, it would give no error and run the code if the value being assigned (or "compared to") was true. This is why it is so important to never mix up the = and == operators, especially when working with booleans.
Hope this helped!!

Categories

Resources