tags:

views:

42

answers:

2

It was such a simple, brilliant idea. Use the power of Java 5.0 enumerated types to encode details of a data dictionary (attribute name, type, range, units, etc.) and create a type-safe system for setting and reading attribute values (i,.e., attribute AAH is short, ACC is enumerated and should only accept the values ACC001, ACC002, ACC003, etc.).

The hitch is that different attributes have different types (integer, float, text, enumerated), and the behaviors for each type are different. So I create a base class with a type parameter and some abstract methods:

public abstract class GsAttributeValueBase<T extends Comparable<T>> {
  protected T m_value;
  ...
  public GsAttributeValueBase(...) {..}
  ...
  public abstract void SetValue(T value) throws IllegalArgumentException;
  public T GetValue() { return m_value; }
  // etc., etc., etc
}

I then subclass this for each type (basically, I'm trying to fake partial specialization):

public class GsAttributeValueShort extends GsAttributeValueBase<Short> {...}
public class GsAttributeValueLong  extends GsAttributeValueBase<Long> {...}
public class GsAttributeValueEncoded extends GsAttributeValueBase<GsAttributeEncodedValueEnum> {...}
...

So far so good. Now I want to basically create a factory method in the attribute enumeration type to return an instance of one of the above subtypes (since each attribute knows its type and range), something like

public GsAttributeValueBase<? extends Comparable<?>> CreateInstance()
{
  switch(m_format)
  {
  case SHORT: return new GsAttributeValueShort(...);
  case LONG: return new GsAttributeValueLong(...);
  case ENCODED: return new GsAttributeValueEncoded(...);
  ...
  }
}

and call the method as:

GsAttributeValueShort = GsAttributeEnum.AAH.CreateInstance();

This is where I hit a brick wall; I get an incompatible types error on the order of

found   : GsAttributeValueBase<capture of ? extends java.lang.Comparable<?>>
required: GsAttributeValueShort

I've tried roughly a dozen permutations on the declaration of CreateInstance() so far (it can't be static, since it relies on information specific to the enumeration instance). I'm about to tear my hair out at this point; I've wasted several days going down this rabbit hole, and need to either get this working today or punt altogether.

I really want to make this work; I think it would be valuable to not just this project but other projects going forward. But Java generics don't behave like C++ templates (something that's been driven home with a vengeance over the past week), and I know I'm missing something vital here, but I can't see what it is.

EDIT

I can't make this work the way I'm envisioning in my head and I've burned too much time on it. Thanks for the suggestions, but I'm going to go ahead and close this down.

EDIT 2

Oh. I can't close my own question. Oh well.

A: 

Just use a map and my TypeSafeMap pattern.

Some thoughts on Generics: Generics are meant to make collections type safe. They aren't really intended for complex things like building type-safe classes at runtime. So be mindful and use your tools so that they don't become a burden. If a cast works and you don't understand how the generic construct works (even if you just wrote it), use the cast. Just imagine coming back to this code in half a year and having to fix it.

Aaron Digulla
"They aren't really intended for complex things like building type-safe classes at runtime." That's a bold statement. I wonder how many people agree.
Kirk Woll
@Kirk: The 90% of the Java developers who are confused when they get a generics-related error message from the Java compiler. What I mean is: Only a few people understand generics well enough to use them for more than type safe collections.
Aaron Digulla
Fair enough. I thought you were implying that generics *can't* be used for other purposes. :)
Kirk Woll
+3  A: 

What about:

public <T extends Comparable<T>> GsAttributeValueBase<? super T> CreateInstance() {
    ...
}
Kirk Woll
Probably also want a `? super` in that and `GsAttributeValueBase`.
Tom Hawtin - tackline
No joy. Now I get incompatible type errors in the CreateInstance() method. If I try to cast the result (return new (GsAttributeValueBase<T>) GsAttributeValueShort(...)), I get an inconvertable type error.
John Bode
Is it an incompatible type error? Or is it "Unchecked cast"? (I was able to compile your sample code with the cast with just a warning.)
Kirk Woll
@Tom, good point, made the change.
Kirk Woll