Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Advanced Java idiom for 2+ classes implementing a generic interface

I came across the following situation and am wondering whether the way I implemented it is good in terms of reusability and speed, I'd also be interested to have an actual compilable solution since the one below doesn't compile (I hope some one finds the culprit and has a simple and elegant idea on this).

There are two Java classes "Vec3F" and "Vec3" that implement basic vector math for floating point and double types. Both implement interface below as follows:

public final class Vec3 implements Vec<Vec3> {
//..
    public double distance(Vec3 other) { /*..*/ }
}

public interface Vec<V> {

    double distance(V other);   
}    

I did this to be able to have some algorithms work with both types of vector implementations, and here comes the problem:

public class Toolbox {

public static <T> double getAllDistances(List<Vec<T>> points) {
    Vec<T> prevPoint = points.get(0);
    Vec<T> point;
    double sum = 0.0;
    int len = points.size();
    for (int i=1;i<len; i++) {
        point = points.get(i);
        //-> this doesn't compile: 
        //The method distance(T) in the type Vec<T> is not applicable for the arguments (Vec<T>)    
        sum+=point.distance(prevPoint);
        prevPoint = point;
    }
    return sum;
}
}

I know that I could implement 'getAllDistances' twice but this is what I want to avoid. I'd love to have a Toolbox class that can do some meta-algorithms based on methods declared in the interface. I also want to avoid to change the method implementation of e.g. distance(Vec3 other) to have the interface passed (because it uses e.g. other.x*other.x directly to avoid calling any getters).

I'd be glad for some thoughts on this and hope the question is clear and specific enough, thanks in advance!

like image 830
RookieGuy Avatar asked Feb 09 '23 02:02

RookieGuy


1 Answers

You probably wanted to define the Vec interface as:

public interface Vec<V extends Vec<V>>

This can be difficult to look at, as it seems at first glance like an illegal forward reference, but it is perfectly valid and normal (and in fact is used in java.lang.Enum).

Whenever you have a Vec<T> instance, you must pass a T, not a Vec<T>, to the distance method. So you would need to define your getAllDistances method like this:

public static <T extends Vec<T>> double getAllDistances(List<T> points) {
    T prevPoint = points.get(0);
    T point;
like image 170
VGR Avatar answered Feb 11 '23 14:02

VGR