0

So this is mainly a Design/Clean Coding sort of question, I know I've read something about this previously but I can't find it, I believe it's in one of my reference books on C/C++ so it wouldn't likely be useful to my predicament.

This question includes a lot of Java code because it seems to be the best way to illistrate what I'm trying to do.

I'm working on a program in Java (so no Operator overloading, which the book I mentioned used). I'm working to isolate the types of data from a buffer class I'm trying to make. The buffers should all be compatable with each other but they can hold any arbitrary object that's a sub-class of my BufferValue interface and Comparable. BufferValue is defined:

/*
 * Copyright © 2012 William Peckham
 */
package paint.buffers;

/**
 * A base class for values that can be put into a paint.buffers.Buffer.
 * An implementer should also override equals and hashCode accordingly
 * @author William Matrix Peckham
 */
public interface BufferValue<T>{
    /**
     * gets the value
     */
    public T getValue();
    /**
     * sets the value
     * @param new value
     * @return previous value
     */
    public T setValue(T v);
    /**
     * sets the value
     * @param new value
     * @return previous value
     */
    public BufferValue<T> setValue(BufferValue<T> v);
    /**
     * Add a value to this one
     * @param second value to add
     * @return result of addition
     */
    public BufferValue<T> add(BufferValue<T> second);

    /**
     * Subtract a value from this one
     * @param second value to subtract
     * @return result of the subtraction
     */
    public BufferValue<T> sub(BufferValue<T> second);

    /**
     * Multiply a value with this one
     * @param second value to be multiplied
     * @return result of the multiplication
     */
    public BufferValue<T> mul(BufferValue<T> second);

    /**
     * Divide this by another value
     * @param second value to divide by
     * @return result of the division
     */
    public BufferValue<T> div(BufferValue<T> second);

    /**
     * get a normalized value of this one based on the minimum and maximums
     * @param min minimum
     * @param max maximum
     * @return normalized result
     */
    public BufferValue<T> normalize(BufferValue<T> min, BufferValue<T> max);

    /**
     * Multiply this value by a double
     * @param t
     * @return 
     */
    public BufferValue<T> mul(double t);
}

but I would like to be able to remove the <T> from the math functions, so that any BufferValue could be multiplied or added to any other BufferValue. The issue being the implementation, with current things looking like:

/*
 * Copyright © 2012 William Peckham
 */
package paint.buffers;

/**
 *
 * @author William Matrix Peckham
 */
public class DoubleValue implements BufferValue<Double>, Comparable<DoubleValue>{
    Double value;

    public DoubleValue(){
        value=0.0;
    }

    public DoubleValue(Double f){
    value=f;
    }
    @Override
    public BufferValue<Double> add(BufferValue<Double> second){
        return new DoubleValue(value+second.getValue());
    }
    @Override
    public BufferValue<Double> sub(BufferValue<Double> second){
        return new DoubleValue(value-second.getValue());
    }
    @Override
    public BufferValue<Double> mul(BufferValue<Double> second){
        return new DoubleValue(value*second.getValue());
    }
    @Override
    public BufferValue<Double> div(BufferValue<Double> second){
        return new DoubleValue(value/second.getValue());
    }
    @Override
    public BufferValue<Double> normalize(BufferValue<Double> min, BufferValue<Double> max){
        return new DoubleValue(((value-min.getValue())/(max.getValue()-min.getValue()))+min.getValue());
    }


    @Override
    public int compareTo(DoubleValue o) {
        return new Double(value).compareTo(o.value);
    }

    @Override
    public boolean equals(Object o){
        if(o instanceof DoubleValue){
            return new Double(value).equals(new Double(((DoubleValue)o).value));
        }
        return false;
    }

    @Override
    public int hashCode(){
        return new Double(value).hashCode();
    }

    @Override
    public Double getValue() {
        return value;
    }

    @Override
    public BufferValue<Double> setValue(BufferValue<Double> v) {
        Double d = value;
        value=v.getValue();
        return new DoubleValue(d);
    }

    @Override
    public Double setValue(Double v) {
        Double vr = value;
        value=v;
        return vr;
    }

    @Override
    public BufferValue<Double> mul(double t) {
        return new DoubleValue(t*value);
    }
}

and

/*
 * Copyright © 2012 William Peckham
 */
package paint.buffers;

import java.awt.Color;

/**
 *
 * @author William Matrix Peckham
 */
public class ColorValue implements BufferValue<Color>, Comparable<ColorValue>{
    Color value;

    public ColorValue(){
        value=new Color(0,0,0);
    }

    public ColorValue(Color c){
        value=c;
    }

    @Override
    public BufferValue<Color> add(BufferValue<Color> second) {
        float[] comps = value.getRGBComponents(null);
        float[] comps1 = second.getValue().getRGBComponents(null);
        float[] rets = new float[4];
        for(int i = 0; i<4; i++){
            rets[i]=comps[i]+comps1[i];
        }
        return new ColorValue(new Color(rets[0], rets[1], rets[2], rets[3]));
    }

    @Override
    public BufferValue<Color> sub(BufferValue<Color> second) {
        float[] comps = value.getRGBComponents(null);
        float[] comps1 = second.getValue().getRGBComponents(null);
        float[] rets = new float[4];
        for(int i = 0; i<4; i++){
            rets[i]=comps[i]-comps1[i];
        }
        return new ColorValue(new Color(rets[0], rets[1], rets[2], rets[3]));
    }

    @Override
    public BufferValue<Color> mul(BufferValue<Color> second) {
        float[] comps = value.getRGBComponents(null);
        float[] comps1 = second.getValue().getRGBComponents(null);
        float[] rets = new float[4];
        for(int i = 0; i<4; i++){
            rets[i]=comps[i]*comps1[i];
        }
        return new ColorValue(new Color(rets[0], rets[1], rets[2], rets[3]));
    }

    @Override
    public BufferValue<Color> div(BufferValue<Color> second) {
        float[] comps = value.getRGBComponents(null);
        float[] comps1 = second.getValue().getRGBComponents(null);
        float[] rets = new float[4];
        for(int i = 0; i<4; i++){
            rets[i]=comps[i]/comps1[i];
        }
        return new ColorValue(new Color(rets[0], rets[1], rets[2], rets[3]));
    }

    @Override
    public BufferValue<Color> normalize(BufferValue<Color> min, BufferValue<Color> max) {
        return new ColorValue(value);
    }


    @Override
    public int compareTo(ColorValue o) {
        int xi = (new Integer(value.getAlpha())).compareTo(o.value.getAlpha());
        if (xi == 0) {
            xi = (new Integer(value.getRed())).compareTo(o.value.getRed());
            if (xi == 0) {
                xi = (new Integer(value.getGreen())).compareTo(o.value.getGreen());
                if (xi == 0) {
                    xi = (new Integer(value.getBlue())).compareTo(o.value.getBlue());
                }
            }
        }
        return xi;
    }
        @Override
    public boolean equals(Object o){
        if(o instanceof ColorValue){
            return value.equals(((ColorValue)o).value);
        }
        return false;
    }

    @Override
    public int hashCode(){
        return value.hashCode();
    }

    @Override
    public Color getValue() {
        return value;
    }

    @Override
    public BufferValue<Color> setValue(BufferValue<Color> v) {
        Color d = value;
        value=v.getValue();
        return new ColorValue(d);
    }

    @Override
    public Color setValue(Color v) {
        Color vr = value;
        value=v;
        return vr;
    }

    @Override
    public BufferValue<Color> mul(double t) {
        float[] comps = value.getRGBComponents(null);
        float[] rets = new float[4];
        for(int i = 0; i<4; i++){
            rets[i]=(float)(comps[i]*t);
        }
        return new ColorValue(new Color(rets[0], rets[1], rets[2], rets[3]));
    }

}

The issue of adding a single double to the Color I'd like to solve by adding the value to all the individual components. How can I make it so I can implement type-type operations like this without having an exponential number of implementations, and without expressly stating which value is being used (BufferValue<Color> ColorBuffer.add(BufferValue<Double>), BufferValue<Color> DoubleBuffer.add(BufferValue<Color>), BufferValue<Color> ColorBuffer.add(BufferValue<Color>), BufferValue<Double> DoubleBuffer.add(BufferValue<Double>)).

2
Contributors
2
Replies
4
Views
5 Years
Discussion Span
Last Post by sciwizeh
0

This problem is related to a classic issue in software engineering, called "Double Dispatching". Many of the most prominent people in the computer science field have discussed this problem, and it seems there is really no generally scalable (non-exponential) solution to this problem, other than converting everything to some common type that can represent everything.

In C++ with templates, this is a non-issue because you can template the functions in terms of the other type, and let the compiler do all the work of generating the different combinations (which are indeed exponential in number).

So, the problem you are reporting is really quite specific to a limitation in the "generics" provided by Java/C#. As far as there being a scalable solution, I doubt there is, unless Java/C# allows for the kind of class template member function templates that C++ allows for.

0

Thanks for the explanation, I don't believe that Java does allow the template member functions like C++ does, so that's a bust I suppose, I really only need two or three types, so I suppose coding them all shouldn't be too hard, I was just hoping for a more scaleable solution.

This question has already been answered. Start a new discussion instead.
Have something to contribute to this discussion? Please be thoughtful, detailed and courteous, and be sure to adhere to our posting rules.