There are some things that don't work, and don't work in rather surprising ways when you compare them to previous functionality of Java's boolean.
We're going to ignore boxing as that was something added with 1.5. Hypothetically, if Sun wanted to they could have made the enum Boolean
to behave just like the boxing performed on the class Boolean
.
Yet, there are other surprising (to the coder) ways that this would suddenly break compared to the functionality of the earlier class.
The valueOf(String) problem
A simple example of this is:
public class BooleanStuff {
public static void main(String args[]) {
Boolean foo = Boolean.valueOf("TRUE");
System.out.println(foo);
foo = Boolean.valueOf("TrUe");
System.out.println(foo);
foo = Boolean.valueOf("yes"); // this is actually false
System.out.println(foo);
// Above this line is perfectly acceptable Java 1.3
// Below this line takes Java 1.5 or later
MyBoolean bar;
bar = MyBoolean.valueOf("FALSE");
System.out.println(bar);
bar = MyBoolean.valueOf("FaLsE");
System.out.println(bar);
}
enum MyBoolean implements Comparable<MyBoolean> {
FALSE(false), TRUE(true);
private MyBoolean(boolean value) { this.value = value; }
private final boolean value;
public boolean booleanValue() { return value; }
public String toString() { return value ? "true" : "false"; }
}
}
The run of this code gives:
true
true
false
false
Exception in thread "main" java.lang.IllegalArgumentException: No enum constant BooleanStuff.MyBoolean.FaLsE
at java.lang.Enum.valueOf(Enum.java:236)
at BooleanStuff$MyBoolean.valueOf(BooleanStuff.java:17)
at BooleanStuff.main(BooleanStuff.java:13)
The problem here is that I can't pass through anything that isn't TRUE
or FALSE
to valueOf(String)
.
That's ok... we'll just override it with our own method...
public static MyBoolean valueOf(String arg) {
return arg.equalsIgnoreCase("true") ? TRUE : FALSE;
}
But... there's a problem here. You can't override a static method.
And so, all the code that is passing around true
or True
or some other case mixed will error out - and quite spectacularly with a runtime exception.
Some more fun with valueOf
There are some other bits that don't work too well:
public static void main(String args[]) {
Boolean foo = Boolean.valueOf(Boolean.valueOf("TRUE"));
System.out.println(foo);
MyBoolean bar = MyBoolean.valueOf(MyBoolean.valueOf("FALSE"));
System.out.println(bar);
}
For foo
, I just get a warning about boxing an already boxed value. However, the code for bar is a syntax error:
Error:(7, 24) java: no suitable method found for valueOf(BooleanStuff.MyBoolean)
method BooleanStuff.MyBoolean.valueOf(java.lang.String) is not applicable
(actual argument BooleanStuff.MyBoolean cannot be converted to java.lang.String by method invocation conversion)
method java.lang.Enum.valueOf(java.lang.Class,java.lang.String) is not applicable
(cannot instantiate from arguments because actual and formal argument lists differ in length)
If we coerce that syntax error back into a String
type:
public static void main(String args[]) {
Boolean foo = Boolean.valueOf(Boolean.valueOf("TRUE"));
System.out.println(foo);
MyBoolean bar = MyBoolean.valueOf(MyBoolean.valueOf("FALSE").toString());
System.out.println(bar);
}
We get our runtime error back:
true
Exception in thread "main" java.lang.IllegalArgumentException: No enum constant BooleanStuff.MyBoolean.false
at java.lang.Enum.valueOf(Enum.java:236)
at BooleanStuff$MyBoolean.valueOf(BooleanStuff.java:11)
at BooleanStuff.main(BooleanStuff.java:7)
Why anyone would write that? Dunno... but its code that used to work and would no longer work.
Don't get me wrong, I really do like the idea of only one copy of a given immutable object ever. The enum does solve this problem. I've personally encountered vendor code that had bugs in it from vendor code that looked something like this:
if(boolValue == new Boolean("true")) { ... }
that never worked (No, I didn't fix it because the incorrect state was fixed somewhere else, and fixing this broke that in strange ways that I really didn't have the time to debug). If this was an enum, that code would have worked instead.
However, the necessities of the syntax around the enum (case sensitive - dig into the enumConstantDirectory behind valueOf
, runtime errors that need to work that way for the other enums) and the way static methods work causes a number of things to break that prevents it from being a drop in replacement for a Boolean.
if
) but from a conceptual/type theory point of view booleans and enums are both instances of sum types, so I think it's fair to ask why they didn't bridge the gap between them.valueOf(String)
(which would conflict with the enum's valueOf) and the magic behindgetBoolean
which can make it so thatBoolean.valueOf("yes")
returns true rather than false. Both of which are part of the 1.0 spec and would need appropriate backwards compatibility.