Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

It seems to me that the Boolean class is an ideal candidate to be implemented as an enum.

Looking at the source code, most of the class is static methods which could be moved unchanged to an enum, the rest become much simpler as an enum. Compare original (comments and static methods removed):

public final class Boolean implements java.io.Serializable,
                                      Comparable<Boolean>
{
   public static final Boolean TRUE = new Boolean(true);
  public static final Boolean FALSE = new Boolean(false);
   private final boolean value;
   public Boolean(boolean value) {
       this.value = value;
   }
   public Boolean(String s) {
       this(toBoolean(s));
   }
   public boolean booleanValue() {
       return value;
   }
   public String toString() {
       return value ? "true" : "false";
   }
   public int hashCode() {
       return value ? 1231 : 1237;
   }
   public boolean equals(Object obj) {
       if (obj instanceof Boolean) {
           return value == ((Boolean)obj).booleanValue();
       }
       return false;
   }
   public int compareTo(Boolean b) {
       return compare(this.value, b.value);
   }
}

with an enum version:

public enum Boolean implements Comparable<Boolean>
{
   FALSE(false), TRUE(true);
   private Boolean(boolean value) {
       this.value = value;
   }
   private final boolean value;
   public boolean booleanValue() {
       return value;
   }

   public String toString() {
       return value ? "true" : "false";
   }
}

Is there any reason why Boolean couldn't become an enum?

share|improve this question
3  
Do you foresee another value for a boolean that isn't true or false? –  MichaelT Mar 28 at 20:05
1  
@MichaelT An enum doesn't need to have more than 2 values. It'd be kind of pointless in Java because it has a specialized statement for processing booleans (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. –  Doval Mar 28 at 20:29
    
Note: You also appear to have missed out on the implementation of valueOf(String) (which would conflict with the enum's valueOf) and the magic behind getBoolean which can make it so that Boolean.valueOf("yes") returns true rather than false. Both of which are part of the 1.0 spec and would need appropriate backwards compatibility. –  MichaelT Mar 28 at 20:35
6  
@MichaelT FileNotFound of course! –  Donal Fellows Mar 28 at 21:56

3 Answers 3

up vote 7 down vote accepted

Well, I guess I could start by arguing that Java enumerations were not added to the Java programming language until the JDK 1.5. and therefore this solution was not even an alternative in the early days when the Boolean class was defined.

That being said, Java has the reputation of keeping backwards compatibility between releases and so, even if we, today, may consider your solution as a good alternative, we cannot do it without breaking thousands of lines of code out there already using the old Boolean class.

share|improve this answer
3  
You might find the Java 1.0 language spec for java.lang.Boolean to be of help. The new Boolean("True") and new Boolean("true") may also cause some problems with the hypothetical enum implementation. –  MichaelT Mar 28 at 20:25
    
It seems wrong to allow multiple (immutable) objects, and so using the provided Constructors on Boolean is not a good idea - as the API documentation says. –  Highland Mark Mar 28 at 22:15
    
The language spec wouldn't help with this sort of question as it doesn't specify the implementations of the Classes. This is how best to implement the specification. –  Highland Mark Mar 28 at 22:26

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.

share|improve this answer
    
Thanks, I enjoyed that! –  Highland Mark Mar 29 at 23:47
1  
If one was designing, from scratch a new language with the knowledge of how Java works (and doesn't), having the Boolean object type be an enum like structure... it just doesn't quite fit with how Java works now. I'm sure there are some language designers kicking themselves for it. If one could start over with Java 8 and things like the default methods in interfaces, I'm sure that a lot of the misfeatures of Java could have been done quite a bit cleaner - at the same time I really do appreciate being able to take a some Java 1.3 code and still compile it in 1.8 - and thats where we are now. –  MichaelT Mar 30 at 0:05
    
It wouldn't have been very difficult to add a of or from method and appropriate javadoc. –  assylias Apr 1 at 23:03
    
@assylias the convention with much of the other java code is valueOf and Boolean.valueOf() has been there since 1.0. Either Enums wouldn't be able to use valueOf as a static method, or Boolean would need a different method than the one it has been using. Doing either breaks convention or compatibility - and not having Boolean be an enum breaks neither. From this, the choice is fairly simple. –  MichaelT Apr 1 at 23:27

Most likely because the primitive boolean type isn't an Enum, and the boxed versions of primitive types behave almost identically to their unboxed version. E.g.

Integer x = 5;
Integer y = 7;
Integer z = x + y;

(The performance may not be the same, but that's a different subject.)

It'd be kind of strange if you could write:

Boolean b = Boolean.TRUE;
switch (b) {
case Boolean.TRUE:
    // do things
    break;
case Boolean.FALSE:
    // do things
    break;
}

but not:

boolean b = true;
switch(b) {
case true:
    // do things
    break;
case false:
    // do things
    break;
}  
share|improve this answer
1  
You might wish to show the if statement that wouldn't work with an enum either. –  MichaelT Mar 28 at 20:20
    
@MichaelT I imagine the compiler would still be able to unbox it and make the if work just like it currently does. On the other hand there's no way to ignore the fact that you've added extra functionality to Boolean that boolean doesn't have. –  Doval Mar 28 at 20:24
    
Whoa... you can't write switch statements for booleans in Java? That's crazy. –  Thomas Eding Mar 28 at 21:58
    
The boxing classes only act like the primitives due to unboxing. Integer doesn't have a + operator. –  Highland Mark Mar 28 at 22:18
    
@HighlandMark That's true, but my point is that they went through great pains to make sure boxed types were usable in the same ways as their primitive counterparts. Unboxing is something they had to implement, it doesn't come for free. –  Doval Mar 29 at 16:41

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.