Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

Consider a situation where a class implements the same basic behavior, methods, et cetera, but multiple different versions of that class could exist for different uses. In my particular case, I have a vector (a geometric vector, not a list) and that vector could apply to any N-dimensional Euclidean space (1 dimensional, 2 dimensional, ...). How can this class / type be defined?

This would be easy in C++ where class templates can have actual values as parameters, but we don't have that luxury in Java.

The two approaches I can think of that could be taken to solve this problem are:

  1. Having an implementation of each possible case at compile time.

    public interface Vector {
        public double magnitude();
    }
    
    public class Vector1 implements Vector {
        public final double x;
        public Vector1(double x) {
            this.x = x;
        }
        @Override
        public double magnitude() {
            return x;
        }
        public double getX() {
            return x;
        }
    }
    
    public class Vector2 implements Vector {
        public final double x, y;
        public Vector2(double x, double y) {
            this.x = x;
            this.y = y;
        }
        @Override
        public double magnitude() {
            return Math.sqrt(x * x + y * y);
        }
        public double getX() {
            return x;
        }
        public double getY() {
            return y;
        }
    }
    

    This solution is obviously very time consuming and extremely tedious to code. In this example it doesn't seem too bad, but in my actual code I'm dealing with vectors that have multiple implementations each, with up to four dimensions (x, y, z, and w). I currently have over 2,000 lines of code, even though each vector only really needs 500.

  2. Specifying parameters at runtime.

    public class Vector {
        private final double[] components;
        public Vector(double[] components) {
            this.components = components;
        }
        public int dimensions() {
            return components.length;
        }
        public double magnitude() {
            double sum = 0;
            for (double component : components) {
                sum += component * component;
            }
            return Math.sqrt(sum);
        }
        public double getComponent(int index) {
            return components[index];
        }
    }
    

    Unfortunately this solution hurts code performance, results in messier code than the former solution, and is not as safe at compile-time (it can't be guaranteed at compile-time that the vector you're dealing with actually is 2-dimensional, for example).

I am currently actually developing in Xtend, so if any Xtend solutions are available, they would also be acceptable.

share|improve this question
    
Since you're using Xtend, are you doing this within the context of an Xtext DSL? – Dan1701 Feb 15 at 23:30
    
@Dan1701 I've never used Xtext for DSLs, nor am I very familiar with how to do that. However, if you have a solution that involves using Xtext, I would be willing to learn :) – Parker Hoyes Feb 15 at 23:34
    
DSLs are great for code-gen applications. In a nutshell, you create a little language grammar, an instance of that language (describing various vectors, in this case), and some code that executes when the instance is saved (generating your Java code). There's plenty of resources and examples on the Xtext site. – Dan1701 Feb 16 at 1:08
    
@Dan1701 Thanks, I'll take a look and put up a post if I find some sort of a solution. – Parker Hoyes Feb 16 at 1:11

I have a very similar model on my application and our solution was to simply keep a map of a dynamic size, similar to your solution 2.

You simply aren't going to need to worry about performance with a java array primative like that. We generate matrixes with upper-bound sizes of 100 columns (read: 100 dimensional vectors) by 10,000 rows, and we have had good performance with much more complex vector types than your solution 2. You might try sealing the class or marking methods as final to speed it up, but I think you're optimizing prematurely.

You can get some code-savings (at the cost of performance) by creating a base class to share your code:

public interface Vector(){

    abstract class Abstract {           
        protected abstract double[] asArray();

        int dimensions(){ return asArray().length; }

        double magnitude(){ 
            double sum = 0;
            for (double component : asArray()) {
                sum += component * component;
            }
            return Math.sqrt(sum);
        }     

        //any additional behavior here   
    }
}

public class Scalar extends Vector.Abstract {
    private double x;

    public double getX(){
        return x;
    }

    @Override
    public double[] asArray(){
        return new double[]{x};
    }
}

public class Cartesian extends Vector.Abstract {

    public double x, y;

    public double getX(){ return x; }
    public double getY(){ return y; }

    @Override public double[] asArray(){ return new double[]{x, y}; }
}

Then of course, if you're on Java-8+, you can use defaulted interfaces to make this even tighter:

public interface Vector{

    default public double magnitude(){
        double sum = 0;
        for (double component : asArray()) {
            sum += component * component;
        }
        return Math.sqrt(sum);
    }

    default public int dimensions(){
        return asArray().length;
    }

    default double getComponent(int index){
        return asArray()[index];
    }

    double[] asArray();

    // giving up a little bit of static-safety in exchange for 
    // runtime exceptions, we can implement the getX(), getY() 
    // etc methods here, 
    // and simply have them throw if the dimensionality is too low 
    // (you can of course do this on the abstract-class strategy as well)

    //document or use checked-exceptions to indicate that these methods throw IndexOutOfBounds exceptions (or a wrapped version)

    default public getX(){
        return getComponent(0);
    }
    default public getY(){
        return getComponent(1);
    }
    //...


    }

    //as a general rule, defaulted interfaces should assume statelessness, 
    // so you want to avoid putting mutating operations 
    // as defaulted methods on an interface, since they'll only make your life harder
}

Ultimately beyond that you're out of options with the JVM. You can of course write them in C++ and use something like JNA to bridge them in --this is our solution for some of the fast matrix operations, where we use fortran and intel's MKL-- but this is only going to slow things down if you simply write your matrix in C++ and call its getters/setters from java.

share|improve this answer
    
My main concern isn't performance, it's compile-time checking. I would really like a solution where the size of the vector and the operations that can be performed on it are determined at compile-time (like with C++ templates). Perhaps your solution is best if you're dealing with matrices that could be up to 1000 components in size, but in this case I'm only dealing with vectors with a size of 1 - 10. – Parker Hoyes Feb 16 at 1:11
    
If you use something like the first or second solution, you can create those subclasses. Now I am also just reading on Xtend, and it seems a fair bit like Kotlin. With Kotlin, you can probably use the data class objects to easily create 10 vector subclasses. With java, assuming you can pull all of your functionality into the base class, each subclass will take 1-10 lines. Why not create a base class? – Groostav Feb 16 at 1:23
    
The example I provided is oversimplified, my actual code has a lot of methods defined for Vector such as the vector dot product, component-wise addition and multiplication, et cetera. Although I could implement these using a base class and your asArray method, those various methods wouldn't be checked at compile time (you could perform a dot-product between a scalar and a cartesian vector and it would compile fine, but fail at runtime). – Parker Hoyes Feb 16 at 1:58

Consider an enum with each named Vector having a constructor that consists of an array (initialized in the parameter list with the dimension names or similar, or perhaps just an integer for the size or an empty components array - your design), and a lambda for the getMagnitude method. You could have the enum also implement an interface for setComponents/getComponent(s), and just establish which component was which in its usage, eliminating getX, et al. You would need to initialize each object with its actual component values before use, possibly checking that the input array size matches the dimension names or size.

Then if you extend the solution to another dimension, you just modify the enum and lambda.

share|improve this answer

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.