Why Java Doesn’t Allow Numeric Conditionals Like C

cjavatype-systems

I have these two little programs:

C

#include <stdio.h>
int main()
{
    if (5) {
        printf("true\n");
    }
    else {
        printf("false\n");
    }

    return 0;
}

Java

class type_system {
   public static void main(String args[]) {
       if (5) {
           System.out.println("true");
       }
       else {
           System.out.println("false");
       }
   }
}

which reports the error message:

type_system.java:4: error: incompatible types: int cannot be converted to boolean
       if (5) {
           ^
1 error

My understanding

So far, I understood this example as a demonstration of the different type systems. C is more weakly typed and allows conversion from int to boolean without errors. Java is more strongly typed and fails, because no implicit conversation is allowed.

Therefore, my question: Where did I misunderstand things?

What I'm not looking for

My question is not related to bad coding style. I know it's bad, but I'm interested in why C does allow it and Java not. Therefore, I'm interested in the language's type system, specifically its strongness.

Best Answer

1. C and Java are different languages

The fact that they behave differently should not be terribly surprising.

2. C is not doing any conversion from int to bool

How could it? C didn't even have a true bool type to convert to until 1999. C was created in the early 1970s, and if was part of it before it was even C, back when it was just a series of modifications to B1.

if wasn't simply a NOP in C for nearly 30 years. It directly acted on numeric values. The verbiage in the C standard (PDF link), even over a decade after the introduction of bools to C, still specifies the behavior of if (p 148) and ?: (p 100) using the terms "unequal to 0" and "equal to 0" rather than the Boolean terms "true" or "false" or something similar.

Conveniently, ...

3. ...numbers just happen to be what the processor's instructions operate on.

JZ and JNZ are your basic x86 assembly instructions for conditional branching. The abbreviations are "Jump if Zero" and "Jump if Not Zero". The equivalents for the PDP-11, where C originated, are BEQ ("Branch if EQual") and BNE ("Branch if Not Equal").

These instructions check if the previous operation resulted in a zero or not and jump (or not) accordingly.

4. Java has a much higher emphasis on safety than C ever did2

And, with safety in mind, they decided that restricting if to booleans was worth the cost (both of implementing such a restriction and the resulting opportunity costs).


1. B doesn't even have types at all. Assembly languages generally don't, either. Yet B and assembly languages manage to handle branching just fine.

2. In the words of Dennis Ritchie when describing the planned modifications to B that became C (emphasis mine):

...it seemed that a typing scheme was necessary to cope with characters and byte addressing, and to prepare for the coming floating-point hardware. Other issues, particularly type safety and interface checking, did not seem as important then as they became later.