1

I have a puzzle about the creation of a structure: an interface Transform that represent a general physical transformation, and a class PoincareTransform that represent a specific type of transformation. I would like to do a thing like this

public interface Transform {
   public Transform compose(Transform t);
}

public class PoincareTransform implements Transform {
   private Matrix matrix;
   public Transform compose(Transform t) {
   ...
   }
}

but I would like that method compose(Transform T) to take only PoicareTransform because is necessary to have a matrix to compose with. A possible solution is using generics

public interface Transform<T extends Transform<T>> {
   public T compose(T t);
}

public class PoincareTransform implements Transform<PoincareTransform> {
   private Matrix matrix;
   public PoincareTransform compose(PoincareTransform t) {
   ...
   }
}

but this is not satisfactory because is not conceptually clean, elegant and there are some trouble again: PoincareTransform subclasses have now the same problem as before. Also, with this definition, I have generics all around my project!

I'm conceptually wrong? How could I build a structure like this that I have in mind?

bluePhlavio
  • 537
  • 5
  • 18
  • 1
    *PoincareTransform subclasses have now the same problem as before.* - I guess the problem you talked about is solved with generics. Can you elaborate a little on your concrete problem? – Rohit Jain Aug 19 '13 at 19:14
  • If I extends PoincarèTransform to get a more specific transformation class, say LorentzTransform, then LorentzTransform can compose with a more general PoicareTransform, and, if this is not a problem of the same gravity as the previous, is a thing that i would discourage. But the worse is that I have generics all around the project because when I use a Transform I need to mantain a generic... – bluePhlavio Aug 19 '13 at 19:28
  • possible duplicate of [Is there a way to refer to the current type with a type variable?](http://stackoverflow.com/questions/7354740/is-there-a-way-to-refer-to-the-current-type-with-a-type-variable) See also: [How can I refer to the type of the current class?](http://stackoverflow.com/questions/18037572/how-can-i-refer-to-the-type-of-the-current-class) and [Assign a subclass of a Generic class to a super class of this class](http://stackoverflow.com/questions/17073920/assign-a-subclass-of-a-generic-class-to-a-super-class-of-this-class) – Paul Bellora Aug 19 '13 at 19:41
  • It looks like you're representing a type tree, that is Transform -> PoincareTransform -> LorentzTransform. Why not create Transform as an abstract class instead of an interface and provide an implementation of your compose method to throw a "Not Supported" exception. This way, only subclasses which override this default behaviour will be able to use the compose method. – Evgheni Crujcov Aug 19 '13 at 19:42
  • The `Transform` class should just be declared as `public interface Transform`. the ` extends Transform` is not useful – newacct Aug 20 '13 at 09:59

2 Answers2

0

I think I would go with your first solution, but return an error if you are unable to get a matrix from the given transform in PoincareTransform.transform(Transform t).

For example:

public class PoincareTransform implements Transform {
   private Matrix matrix;
   public Transform compose(Transform t) {
     if (!t.hasMatrix()) {
       // Throw an exception, or some other meaningful error.
     }
     ...
   }
}

This way, it is generic so that if you do end up with a different kind of transform with a matrix, then you can use it.

On the other hand, if you really only want to operate on PoincareTransforms, you can check to see if the instance passed in is correct using the instanceof operator.

public class PoincareTransform implements Transform {
   private Matrix matrix;
   public Transform compose(Transform t) {
     if (!t instanceof PoincarTransform) {
       // Throw an exception, or some other meaningful error.
     }
     PoincarTransform p = (PoincarTransform)t;
     ...
   }
}
Trenin
  • 2,041
  • 1
  • 14
  • 20
0

You're talking about covariant argument types, and I don't believe you can encode this in java's type system. It would violate Liskov's principle: if the supertype declares that it can accept values of some type T, subtypes must at least accept as much. (What is allowed though is contravariant argument types: a subtype could accept more types than its supertype (in your case, Liskov would allow PoincoreTransform.compose to accept Objects instead of Transforms), but again this is AFAIK not supported in java.)

IMHO the cleanest solution would be to abandon the idea of having compile time checks and settle for runtime checks: use an instanceof in subtypes to ensure that the argument is of the correct subtype of Transform (as shown by the poster before me).