In Java is boolean cast useless? - java

I see that the explicit cast syntax for boolean (boolean) is syntactically legal, but I can't think of a use for it. The corresponding Boolean object -- or rather casting back and forth between boolean and Boolean -- is handled by autoboxing. So it seems like a useless language artifact of the compiler. Is there a functional scenario I am missing?

It can make a difference when an overloaded method is called. Since the method to call is determined by the static type(s) of the parameter(s) (See JLS, §15.12.2), casting a Boolean to a boolean or vice-versa can change which method is called:
class Ideone {
public static void main (String[] args) {
final Boolean b = true;
foo((boolean) b); // prints out "primitive"
foo(b); // prints out "wrapper"
}
public static void foo(boolean b) {
System.out.println("primitive");
}
public static void foo(Boolean b) {
System.out.println("wrapper");
}
}
Ideone Demo
Notice that when casting from Boolean to boolean, a NullPointerException may occur when the Boolean has a value of null.
Whether this behaviour is (extensively) used or should be used is another debate, however.
rzwitserloot showed another case with boolean and Object in their answer. While rzwisterloot's case seems similar, the underlying mechanism is different since the downcast from Object to boolean is defined separately in the JLS. Furthermore, it is prone to a ClassCastException (if the Object is not a Boolean) aswell as a NullPointerException (if the Object is null).

Not entirely.
Ordinarily, applying the cast operator with a primitive type serves only one purpose, which is to convert one primitive type to another. boolean is the only primitive type with the property that nothing can be converted to a boolean, and a boolean cannot be converted to anything else.
But, there is a second purpose to these, although it's not exactly spelled out in the JLS and is a dubious code style practice: It effectively causes auto-unboxing to trigger. And it even combines the job of triggering auto-unbox and an ordinary type cast:
Object o = true;
boolean b = (boolean) o;
o = "Hello";
b = (boolean) o;
compiles just fine. It'll cause a ClassCastException on the 4th line, as expected. Without the boolean cast, you'd have to do something like:
boolean b = ((Boolean) o).booleanValue();
which is definitely more wordy. Exactly how often you end up wanting to cast some expression of type Object to boolean - probably that's a very rare occurrence, but it is a real one, and disallowing (boolean) would have made the JLS longer, not shorter (and the javac codebase wouldn't be any shorter either).

As stated in other answers, you can use a cast to boolean to enforce auto-unboxing or to select from overloaded methods. As a special case, calling invokeExact on MethodHandle may require such a cast to select the right method signature, even for the return type.
But there was a time when neither of these features existed, still, a boolean cast was allowed. Adding a special rule for boolean would not make the language simpler. But the implications of allowing this feature had been considered.
When we look into second edition of the language specification:
5.1.1 Identity Conversions
A conversion from a type to that same type is permitted for any type.
This may seem trivial, but it has two practical consequences. First, it is always permitted for an expression to have the desired type to begin with, thus allowing the simply stated rule that every expression is subject to conversion, if only a trivial identity conversion. Second, it implies that it is permitted for a program to include redundant cast operators for the sake of clarity.
The only permitted conversion that involves the type boolean is the identity conversion from boolean to boolean.
So back then, a boolean value could only be cast to boolean, that was even stated explicitly, but was intentionally allowed, e.g. “for the sake of clarity”.
Consider a call like foo(bar()) vs. foo((boolean)bar()).
Or, stringBuffer.append((boolean)someMethod()).
The cast could not alter the behavior of the program but provide additional information to the human reader.
Today’s version still states that identity conversions are allowed, but does not restrict the conversions of boolean to identity conversion, as we now can convert between boolean and reference types.
There’s even a second mentioning in the old version:
15.16 Cast Expressions
A cast expression converts, at run time, a value of one numeric type to a similar value of another numeric type; or confirms, at compile time, that the type of an expression is boolean; or checks, at run time, that a reference value refers to an object whose class is compatible with a specified reference type.
Since conversions between primitive types and reference types were not possible back then, there were three distinct use cases for casts, numeric conversions, reference type changes, or it “confirms, at compile time, that the type of an expression is boolean”.
As that’s the only thing a boolean cast could do in that Java version.

Related

Ambiguous method call with Integer

I am writing some Junit tests in Android, and if i do this:
public void testSetId(){
Friend friend = new Friend(5);
assertEquals(5,friend.getId());
}
I get an ambiguous method call error.
Ambiguous Method Call:
Both AssertEquals(int, int) and
AssertEquals(Object, Object) match
Yet If i do this:
public void testSetId(){
Integer ID = 5;
Friend friend = new Friend(ID);
assertEquals(ID, friend.getId());
}
It works. I feel like the second function should be doing the exact same thing.
What is going on here?
Before Java 5 there was no autoboxing or auto-unboxing. This meant that if a method foo had a parameter of type Integer, the following did not compile
foo(5); // 5 needs to be autoboxed
Similarly, if a method bar had a parameter of type int, this did not compile
bar(new Integer(5)); // The Integer needs to be unboxed
When autoboxing and auto-unboxing were introduced, it was essential for existing code to continue to work in exactly the same way as before. Therefore when the compiler decides which method is being called, it first considers only the applicable methods that do not require autoboxing or auto-unboxing. Only if there are no such methods does the compiler consider methods requiring autoboxing and/or auto-unboxing.
Since getId returns an Integer, the Object, Object method can be called without autoboxing in the case when the first argument is also an Integer. However the int, int method can only be called by auto-unboxing the second parameter. Therefore in your second example, the Object, Object overload is selected on the first pass.
In your first example, you are trying to pass an int and an Integer. The int, int method applies only by auto-unboxing the second argument, while the Object, Object method applies only by autoboxing the first argument. Therefore the overload cannot be chosen on the first pass, and because neither method is more specific than the other (you'll need to look that last bit up) the compiler cannot choose between the two methods.
Overload resolution is extremely complicated, and I've actually simplified it quite a bit (there are also rules involving var-args). However in practice, you don't need to learn all these rules - if ever you need to tell the compiler which method to apply you can always include an explicit cast or casts:
assertEquals((Integer) id, friend.getId());

Unbound generic return type in Java

I am playing with some ideas about constructing Java APIs and today I spent some time thinking about this code:
public <T> T getField1(Class<?> type, Class<T> retvalType, String fieldName) {
Object retval = ...; // boring reflection code - value could be dog, could be duck
return retvalType.cast(retval); // cast to expected - exception is raised here
}
// usage - we manually repeat the LHS type as a parameter
int foo = getField(o, Integer.class, "foo");
This is how I would typically write the API, witht he idea that specifying the retvalType gives me extra type safety. But does it?
Because we have reflection involved, the retval type is unknown. Casting on the second line would reliably catch type mismatch only when retvalType is non-generic. On the other hand, even if we don't do this explicit cast, the Java runtime would cast the generic result when it sets it to a variable - in other words, are there any drawbacks if we rewrite the code above as:
public <T> T getField2(Class<?> type, String fieldName) {
return ...; // boring reflection code - the value type will be checked when we assign it
}
// usage - exception is raised at the next line if types don't match
int foo = getField(o, "foo");
The advantage of the latter code is that the usage is more compact and we don't have to repeat ourselves. The disadvantage is that type cast exceptions come from non-obvious place (there is no explicit cast at the calls site), but I'm starting to think that that is OK - by specifying type literal, we only repeat what we already know, but ultimately because of reflection the program soundness is still not guaranteed.
Can anybody make a good argument why the first snippet would be preferable to the second?
Edit 1:
One argument is that by having the expected type as a parameter, we can accommodate a need to do non-trivial coercion without changing the API.
For example, the looked-up field may be of type Date, but we may be requesting long, which could be converted internally by doing date.getTime(). Still this seems far-fetched to me and there is risk of mixing responsibilities.
On the other hand, not passing the type limits the input dependencies, which makes the API more robust to changes. (Cue in 'information hiding', 'instability metric', etc).
In conversation with #shmosel it came up that the runtime cast, on which the second version relies, will not necessarily happen when the LHS type is generic type.
For example, consider the code:
class Foo<T> {
void a1(Object o) {
// forces to be explicit about the chance of heap polution
#SuppressWarning("unchecked")
Set<String> a = (Set<String>) getField1(o, Set.class, "foo");
T c = (T) getField1(o, Set.class, "foo"); // guaranteed not to compile
}
void a2(Object o) {
// implicit chance of heap polution in case of Set<Date>
Set<String> a = (Set<String>) getField2(o, "foo");
T c = getField2(o, "foo"); // will succeed even if foo is Date
}
}
In other words, by doing the casting in the getField() method, we get a hard guarantee that the value is of the specified class, even if it is not used, or assigned to an Object variable (which happens often in dynamic languages and reflective libraries).

Java Object return type vs. Generic Methods

I saw several questions about generic return type, but none answers my question.
If there is no bound for any of the arguments, such as the following method in JayWay :
public static <T> T read(String json, String jsonPath, Filter... filters) {
return new JsonReader().parse(json).read(jsonPath, filters);
}
What is the point of using this as generic ?
I told the guys from my team that this method should be used as :
JsonPath.<Boolean>read(currentRule, "$.logged")
instead of:
(boolean) JsonPath.read(currentRule, "$.logged")
But I really can't tell the difference...
Generics work by the compiler inserting invisible casts into your code.
For example, before generics were added to the language you'd have to do this.
List list = new ArrayList();
list.add("Foo");
list.add("Bar");
String str0 = (String) list.get(0);
String str1 = (String) list.get(1);
This was very annoying. Because get() returned Object, you had to cast every single time you wanted to get a String from the List.
Nowadays, List is generic, and get() returns T, so you can just do this.
List<String> list = new ArrayList<>();
list.add("Foo");
list.add("Bar");
String str0 = list.get(0);
String str1 = list.get(1);
What is happening here is that the compiler turns the new version into the old version by adding the casts for you, but they're still there.
However, the entire point of generics is that these compiler generated casts are guaranteed to be safe - i.e. they can't possibly throw a ClassCastException at runtime.
In my opinion, if you use generics to hide casts that are not guaranteed to be safe, just because they're annoying, it is an abuse of the feature.
Whether it's a generic method and you do
Boolean a = JsonPath.<Boolean>read(currentRule, "$.logged");
or it returns Object and you do
Boolean a = (Boolean) JsonPath.read(currentRule, "$.logged");
both versions could throw a ClassCastException at runtime, so I think it's better if you are forced to cast so that at least you are aware that you're doing something that could fail.
I consider it bad practice for the return type of a generic method to involve the type parameter T if the method parameters do not, unless the returned object cannot be used in a way that compromises type safety. For example,
public static <T> List<T> emptyList()
in Collections is ok (the list is empty so it can't contain an element of the wrong type).
In your case, I think the read method should not be generic and should just return Object.
The main reason that I would stay away from
JsonPath.<Boolean>read(currentRule, "$.logged")
is that it is internally performing an unchecked cast, and hiding this fact. For instance, you could invoke this method at the same place:
JsonPath.<String>read(currentRule, "$.logged")
and there is no way that you'd know there might be a problem there until it actually happens at runtime - it still compiles, and you don't even get a warning.
There is no getting away from the unchecked cast - I'd just rather have it right there in front of me in the code, so I know there is a potential danger; this allows me to take reasonable steps to mitigate the issue.
#SuppressWarnings("unchecked") // I know something might go wrong here!
boolean value = (boolean) JsonPath.read(currentRule, "$.logged")
Having a type-parameter that has never been set (when calling JsonPath.read(currentRule, "$.logged")), actually makes the compiler completely ignore all the generic information within the method and replace all the type-parameter with:
Object, if the type-parameter doesn't have an upper-bound. (like in your case)
U, if the type-parameter is bounded like <T extends U>. For example, if you have a <T extends Number> as a type-parameter and ignore it by calling JsonPath.read(...), then the compiler will replace the type-parameter with Number.
In the case with the cast ((boolean) JsonPath.read(...)), the type-parameter is replaced with Object. Then, this type is unsafely transformated to boolean, by first returning a Boolean (probably), and then auto-unboxing this wrapper to boolean. This is not safe, at all. Actually, every cast is not safe - pretty much you tell the compiler: "I know what this type will be at Runtime, so please believe me, and let me cast it to something else that's compatible with it.". Your humble servant, the compiler, allows that, but that's not safe, if you're wrong. :)
There's another thing with your method, also. The type-parameter is never used within the method body or parameters - this makes it pretty redundant. Since by doing a cast to boolean you insist that you know the return type of new JsonReader().parse(json).read(jsonPath, filters);, then you should just make the return type boolean (or Boolean):
public static Boolean read(String json, String jsonPath, Filter... filters) {
return new JsonReader().parse(json).read(jsonPath, filters);
}
There is nothing functionally different between the two. The byte-code will probably be identical.
The core difference is that one uses a cast while the other uses generics.
I would generally try to avoid casting if there is any alternative mechanism and as the generic form is a perfectly effective alternative I would go for that.
// The right way.
JsonPath.<Boolean>read(currentRule, "$.logged");

Generics, need layman explanation?

I came across the following snippet of code that uses generics.
public class Generics<T> {
public static <T> T replaceIfNull(T objectToCheck, T defaultValue) {
return objectToCheck == null ? defaultValue : objectToCheck;
}
public static <T> boolean CheckIfNull(T objectToCheck) {
return objectToCheck == null ? true : false;
}
}
I am having a difficult time truly understanding how generics work, formed and used. I have a high level understanding, meaning that I know the definition of generics. And by the definition my interpretation of this code snippet is that replaceIfNull method checks for null values of any object and then returns a default value (whatever that is). And that CheckIfNull method is similar, in that it checks null value for any object.
But how does this work? Why is the method formed with <T>, which seems to be a type and then there is T following. I do not understand this syntax, <T> T means? And how does T become a type in the parameters? How come this method, for example, could not be written as
public static Object replaceIfNull(Object objectToCheck, Object defaultValue) {
return objectToCheck == null ? defaultValue : objectToCheck;
}
Thank you in advance for your clarification.
Let's start with answering your last question. The method rewrite with Object instead of generics has two drawbacks. First, it will not work with primitives (which might not be a real drawback in this case, since you are checking against null, and primitives cannot take null values, but still...). Second, it will require casting. If , for example, you use this method on two strings, like replaceIfNull(myString, "Default Value"), then you would expect to get a String as an output, right? But instead the method declared to be returning Object; so there is no way for compiler to know that it will return a String, and you will have to do casting every time you use it: `String result = (String) replaceIfNull(myString, "Default Value");' Generics were introduced specifically to fix this situation.
You can think of generics as templates; whatever type you put in the angle braces will be used later in the code whenever you use type parameter. So, <T> means: "Here will go some type; replace T with it everywhere in the code".
And the last question is about the method signature. I think here you mixed up two different methods of using generics - on a class level, and on a method level. Since you've already introduced the type parameter on the class level, there is no need to do it again on a method level, so I think you can safely remove <T> from method declaration.
I suggest you read a more detailed explanation on generics here: http://docs.oracle.com/javase/tutorial/java/generics/
The subject of Generics is very broad and you can read about it extensively on Oracle's website or on Stack Overflow.
Why is the method formed with <T>, which seems to be a type and then there is T following.
This is a generic method. The <T> declares a new type variable with no bounds.
// v return type
public static <T> T replaceIfNull(T objectToCheck, T defaultValue) {
// ^ new type variable ^ type variable used as a type
Within the method body, since the type variable has no bounds, T can, at most, be interpreted as Object. You're only going to have access to method declared in Object on expressions of type T.
Outside the method, ie. in invocation contexts, the type variable T will receive a concrete type value. That is, it will either infer it from its invocation context or it will be provided explicitly.
For example, in
replaceIfNull(someStringVar, otherStringVar);
the type variable T will be bound to String, so all usages of T will be interpreted as String. You could therefore do
String notNull = replaceIfNull(someStringVar, " not null ");
You could also provide the type argument explicitly
Generics.<String>replaceIfNull(nullVar, " not null ");
and now again the type variable will be bound to String.
Note that the type variable T declared at the type level
public class Generics<T>
is completely different from the type variable T declared in the method.

Why does autoboxing make some calls ambiguous in Java?

I noticed today that auto-boxing can sometimes cause ambiguity in method overload resolution. The simplest example appears to be this:
public class Test {
static void f(Object a, boolean b) {}
static void f(Object a, Object b) {}
static void m(int a, boolean b) { f(a,b); }
}
When compiled, it causes the following error:
Test.java:5: reference to f is ambiguous, both method
f(java.lang.Object,boolean) in Test and method
f(java.lang.Object,java.lang.Object) in Test match
static void m(int a, boolean b) { f(a, b); }
^
The fix to this error is trivial: just use explicit auto-boxing:
static void m(int a, boolean b) { f((Object)a, b); }
Which correctly calls the first overload as expected.
So why did the overload resolution fail? Why didn't the compiler auto-box the first argument, and accept the second argument normally? Why did I have to request auto-boxing explicitly?
When you cast the first argument to Object yourself, the compiler will match the method without using autoboxing (JLS3 15.12.2):
The first phase (§15.12.2.2) performs
overload resolution without permitting
boxing or unboxing conversion, or the
use of variable arity method
invocation. If no applicable method is
found during this phase then
processing continues to the second
phase.
If you don't cast it explicitly, it will go to the second phase of trying to find a matching method, allowing autoboxing, and then it is indeed ambiguous, because your second argument can be matched by boolean or Object.
The second phase (§15.12.2.3) performs
overload resolution while allowing
boxing and unboxing, but still
precludes the use of variable arity
method invocation.
Why, in the second phase, doesn't the compiler choose the second method because no autoboxing of the boolean argument is necessary? Because after it has found the two matching methods, only subtype conversion is used to determine the most specific method of the two, regardless of any boxing or unboxing that took place to match them in the first place (§15.12.2.5).
Also: the compiler can't always choose the most specific method based on the number of auto(un)boxing needed. It can still result in ambiguous cases. For example, this is still ambiguous:
public class Test {
static void f(Object a, boolean b) {}
static void f(int a, Object b) {}
static void m(int a, boolean b) { f(a, b); } // ambiguous
}
Remember that the algorithm for choosing a matching method (compile-time step 2) is fixed and described in the JLS. Once in phase 2 there is no selective autoboxing or unboxing. The compiler will locate all the methods that are accessible (both methods in these cases) and applicable (again the two methods), and only then chooses the most specific one without looking at boxing/unboxing, which is ambiguous here.
The compiler did auto-box the first argument. Once that was done, it's the second argument that's ambiguous, as it could be seen as either boolean or Object.
This page explains the rules for autoboxing and selecting which method to invoke. The compiler first tries to select a method without using any autoboxing at all, because boxing and unboxing carry performance penalties. If no method can be selected without resorting to boxing, as in this case, then boxing is on the table for all arguments to that method.
When you say f(a, b), the compiler is confused as to which function it should reference to.
This is because a is an int, but the argument expected in f is an Object. So the compliler decides to convert a to an Object. Now the problem is that, if a can be converted to an object, so can be b.
This means that the function call can reference to either definitions. This makes the call ambiguous.
When you convert a to an Object manually, the compiler just looks for the closest match and then refers to it.
Why didn't the compiler select the
function that can be reached by "doing
the least possible number of
boxing/unboxing conversions"?
See the following case:
f(boolean a, Object b)
f(Object a , boolean b)
If we call like f(boolean a, boolean b), which function should it select? It ambigous right? Similarly, this will become more complex when a lot of arguments are present. So the compiler chose to give you a warning instead.
Since there is no way to know which one of the functions the programmer really intended to call, the compiler gives an error.
So why did the overload resolution
fail? Why didn't the compiler auto-box
the first argument, and accept the
second argument normally? Why did I
have to request auto-boxing
explicitly?
It didn't accept the second argument normally. Remember that "boolean" can be boxed to an Object too. You could have explicitly cast the boolean argument to Object as well and it would have worked.
See http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#20448
The cast helps because then no boxing is needed to find the method to call. Without the cast the second try is to allow boxing and then also the boolean can be boxed.
It is better to have clear and understandable specs to say what will happen than to make people guess.
The Java compiler resolves overloaded methods and constructors in phases. In the first phase [§15.12.2.2], it identifies applicable methods by subtyping [§4.10]. In this example, neither method is applicable, because int is not a subtype of Object.
In the second phase [§15.12.2.3], the compiler identifies applicable methods by method invocation conversion [§5.3], which is a combination of autoboxing and subtyping. The int argument can be converted to an Integer, which is a subtype of Object, for both overloads. The boolean argument needs no conversion for the first overload, and can be converted to Boolean, a subtype of Object, for the second. Therefore, both methods are applicable in the second phase.
Since more than one method is applicable, the compiler must determine which is most specific [§15.12.2.5]. It compares the parameter types, not the argument types, and it doesn't autobox them. Object and boolean are unrelated types, so they are considered equally specific. Neither method is more specific than the other, so the method call is ambiguous.
One way to resolve the ambiguity would be to change the boolean parameter to type Boolean, which is a subtype of Object. The first overload would always be more specific (when applicable) than the second.

Categories