I'm A Ternary Expression, What's My Type?

I was rather annoyed today to find yet another difference between the Eclipse Java compiler, and the Sun Java compiler (1.5, in both cases). Today's challenge was with a ternary expression. I had code with the following structure:
package dummy;
interface Proxy {}

abstract class Base {
 Base(Base owner) {}
}

abstract class TypedBase extends Base {
  TypedBase(Base owner) {super(owner);}
}

class ObjectClass extends TypedBase implements Proxy {
  public ObjectClass() {
    super(null);
  }
}

class SubType extends Base implements Proxy {
  SubType(ObjectClass owner) {
    super(owner);
  }
}

class ObjectProperty extends TypedBase implements Proxy {
  public ObjectProperty(ObjectClass objectClass, SubType optionalSubType) {
    super(optionalSubType == null ? objectClass : optionalSubType);
  }
}
This code compiled fine with Eclipse, but not with the Sun compiler, which complained as follows:
CompilerTest.java:[27,4] cannot find symbol
symbol  : constructor TypedBase(java.lang.Object&dummy.Proxy&dummy.Base)
location: class dummy.TypedBase

CompilerTest.java:[27,4] cannot find symbol
symbol  : constructor TypedBase(java.lang.Object&dummy.Proxy&dummy.Base)
location: class dummy.TypedBase
It appears that Eclipse has determined the type of the ternary expression to be dummy.Base (makes sense to me), but the Sun compiler seems to have employed the Java Generics facilities which allow one to have multiple constraints on a type variable. Reading the Java Language Specification, the Sun compiler appears to be doing what the spec says, which is little consolation. I found a bug report that explains the problem in more detail, and requests that the spec for the ternary expression be fixed to avoid this problem (which I think would make the spec line up with the Eclipse compiler's behavior).
There is of course a simple fix: add a cast to the desired type, Base in this case. I actually chose to create a helper method as shown below because I find ternary expressions problematic to debug (i.e. I prefer to have if/then/else statements, which allow me to set separate breakpoints on the branches of the if).
class ObjectProperty extends TypedBase implements Proxy {
  public ObjectProperty(
      ObjectClass objectClass,
      SubType optionalSubType) {
    super(chooseOwner(objectClass, optionalSubType));
  }
  private static Base chooseOwner(
      ObjectClass objectClass,
      SubType optionalSubType) {
    if (optionalSubType == null)
      return objectClass;
    else
      return optionalSubType;
  }
}

Popular Posts