64

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?

David Neuschulz
  • 959
  • 1
  • 8
  • 14
  • What made you think of this little obscurity? – Robert Harvey Mar 01 '21 at 22:02
  • 11
    **Thought experiment:** Is it easier (on everyone) to build a compiler that pedantically points out all of these "useless language artifacts" when they occur, or one that simply does the right thing if such an artifact is encountered? – Robert Harvey Mar 01 '21 at 22:07
  • 16
    Well [there is one little conrner-case I came up with](https://ideone.com/FDg0VE). If this, however, is or should be used is another debate... – Turing85 Mar 01 '21 at 22:08
  • 2
    Maybe this could come up in the context of custom deserialisation. When you're getting a bunch of `Object`s, but you know one of them is of type `boolean`? – QBrute Mar 01 '21 at 22:08
  • 1
    Studying for the OCA cert exam. – David Neuschulz Mar 01 '21 at 22:08
  • 1
    I haven't taken it yet, so I have no idea. Not faulting the compiler at all. You come up with a grammar and stick with it. Turing85's answer show a functional use, although, yes, I'd say it could be pursued elsewhere in a "is this a best practice?" type debate. – David Neuschulz Mar 01 '21 at 22:15
  • My default assumption whenever I find something I think is -- upon first impression -- "useless" or "broken" is to assume that it's my own brain that is broken (although not totally useless). I'd say 99.9% I am wrong. It has served me well. I can't see how you can become a xen master of any tech without this reflex. – David Neuschulz Mar 01 '21 at 22:18
  • 1
    fun fact: in C you can also do `(void)` – user253751 Mar 02 '21 at 18:08
  • 2
    @user253751 but there _is_ a good use for it both in C and C++ (although not mandated by the Standards): see [What does casting to `void` really do?](https://stackoverflow.com/q/34288844/673852) – Ruslan Mar 02 '21 at 19:09
  • 1
    But Java didn't always have autoboxing/unboxing, right? I mean, in the distant past ... So maybe it was useful then? – davidbak Mar 03 '21 at 02:35
  • 2
    @davidbak actually, it’s the opposite. Back then, when there was no autoboxing nor method handles, it had an even less usefulness. – Holger Mar 03 '21 at 14:03
  • 2
    @davidbak [I did the archeology](https://stackoverflow.com/a/66459145/2711488), to verify that in the ancient Java versions, a boolean cast could do even less than today, i.e. only cast from `boolean` to `boolean`. – Holger Mar 03 '21 at 14:37

3 Answers3

102

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).

Turing85
  • 18,217
  • 7
  • 33
  • 58
  • 19
    It’s not uncommon to have overloaded methods accepting `boolean` and `Object` (example: `String.valueOf(…)`). A call with a `Boolean` would also use the method with an `Object` parameter. – Martin Mar 02 '21 at 17:53
  • 2
    That is not the point here. Having overloaded methods `foo(boolean bar)` and `foo(Boolean bar)` with different implementations is a recipe for disaster. – Turing85 Mar 02 '21 at 18:21
  • 3
    @Turing85 it sounds like a valid point to me. :) – Alvin Thompson Mar 02 '21 at 18:27
  • 7
    Indeed, this answer would be better with `boolean`/`Object`, which is a lot more realistic – OrangeDog Mar 02 '21 at 23:09
  • 1
    @OrangeDog that would just be a copy of rzwitserloot's answer. Furthermore, the mechanisms shown are two separate effects. i have expanded my answer to reference rzwitserloot's answer, and a little bit of explanation on the difference between the answers. – Turing85 Mar 03 '21 at 07:09
  • 2
    note that a well designed system would have both possible methods returning the same result. Otherwise, you're just begging for bugs. – corsiKa Mar 03 '21 at 08:14
  • 4
    As a special case, when calling `invokeExact` on a `MethodHandle` you may need this, even when the actual target method is not overloaded. It may be even necessary for the return type. – Holger Mar 03 '21 at 13:52
26

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).

Skrelp
  • 181
  • 2
  • 16
rzwitserloot
  • 85,357
  • 5
  • 51
  • 72
  • 1
    "*... it's not exactly spelled out in the JLS ...*" - What exactly do you mean by this? The JLS can, at times, be cryptic. But if this is not mentioned whatsoever, I would never assume it to work. In particular, it could break if we switch from one TCK-compatible Java-distribution to another TCK-compatible Java-distribution. – Turing85 Mar 01 '21 at 22:20
  • 11
    It is in fact explicitly spelled out: https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.5 – Octavia Togami Mar 02 '21 at 08:50
  • 6
    `boolean b = (Boolean)o;` – user253751 Mar 02 '21 at 09:32
14

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.

Holger
  • 285,553
  • 42
  • 434
  • 765