4

I'm writing a function to sum two arrays (of not necessarily equal size) in Java and return the result.

Here's my attempt:

 public static <T> T[] sumArrays(T[] lhs, T[] rhs)
    {
        T[] out = new T[Math.max(lhs.length, rhs.length)];

        for (int i = 0; i < Math.max(lhs.length, rhs.length); ++i){            
            if (i < Math.min(lhs.length, rhs.length)){
                out[i] = lhs[i] + rhs[i];                
            } else if (i < lhs.length){
                out[i] = lhs[i];
            } else /* if (i < rhs.length)*/{
                out[i] = rhs[i];
            }            
        }
        return out;        
    }

But I have several observations notwithstanding the compile errors.

  1. Why isn't this function in the Java library, which is gigantic in the extreme?

  2. I was motivated to use generics, as you would use templates in C++.

  3. I'm worried about getting deep copies of the input data; lhs and ``rhs. Can anyone reassure me on this? C++ allows me to pass a constant reference; and I'll know for sure.

  4. Instantiation of T[] out appears to be illegal with a generic type. What am I missing?

  5. Will the compiler optimise out my repeated Math.max(lhs.length, rhs.length)?

  6. Compiler doesn't like lhs[i] + rhs[i]. Presumably because it doesn't know the type of T, but C++ allows you do to this as it will not attempt to compile a template until it knows the type.

  7. Are going to take a deep copy of out when returning? Again, C++ compilers would not take an extra copy.

Perhaps I'm too old to get used to Java;-)

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
  • Ad 3) http://javadude.com/articles/passbyvalue.htm – Anders R. Bystrup Jul 01 '13 at 10:14
  • Adding the contents of two arrays of uneven length is not eactly a common activity, i've never done it. If it was then what about dividing two arrays, subtracting two arrays, raising one entry from one array to the power of the other etc etc etc. Java gives you the tools to do it if you need it – Richard Tingle Jul 01 '13 at 10:15
  • 1
    `T` is unknown at runtime which is why you can't do `new T[]` – blank Jul 01 '13 at 10:15
  • 4
    And + is only available for primatives (and strings) not all objects so given that you've declared this function as being prepared to take **anything** the compiler can't let you use + – Richard Tingle Jul 01 '13 at 10:16

2 Answers2

9

1) Why isn't this function in the extremely gigantic Java library?

Asking for opinion, off-topic here.

3) I'm worried about getting deep copies of the input data; lhs and rhs. Can anyone reassure me on this? C++ allows me to pass a constant reference; and I'll know for sure.

7) Are going to take a deep copy of out when returning? Again, C++ compilers would not take an extra copy.

No deep copying is ever done automatically in Java. Furthermore, deep copying is an ill-defined problem in general.

4) Instantiation of T[] out appears to be illegal with a generic type. What am I missing?

Apart from it being impossible to instantiate an array of generic type, generic types only cover reference types. You are quite probably interested only in primitive types here, so they are of no use.

5) Will the compiler optimise out my repeated Math.max(lhs.length, rhs.length)?

Some JITs might, but you can't have any kind of guarantee. Extract to a local variable.

6) Compiler doesn't like lhs[i] + rhs[i]. Presumably because it doesn't know the type of T, but C++ allows you do to this as it will not attempt to compile a template until it knows the type.

Unfortunately, you are in a lot of trouble here. There is no way to generify algorithms to all primitive Java types.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
Marko Topolnik
  • 195,646
  • 29
  • 319
  • 436
  • Hum, but +1. It's not to be construed as a criticism as Java owes its elegance in its considering how to improve other languages, but the above would have all been easily accomplished in C++ using templates. I guess I should build a version using double in place of T. – Bathsheba Jul 01 '13 at 10:21
  • @Bathsheba In C++ what happens if you try to (for example) add a basketball to annother basketball? As written your code allows this (if the compiler didn't object) – Richard Tingle Jul 01 '13 at 10:23
  • 2
    C++ templates are instantiated at compile time with specific types, so they have precious little to do with Java Generics. Yes, JG is quite a limp feature of Java, having a terrible thrust-to-weight ratio, and has already received a lot of criticism to that effect. – Marko Topolnik Jul 01 '13 at 10:24
  • 1
    @Richard Tingle; in C++ you can overload operators if the operation is meaningful, or allow (or even force) a compile-time error if it's not. – Bathsheba Jul 01 '13 at 10:24
  • @Bathsheba However the signature of this states explicely that it will take anything (like an arraylist will take anything), it would in fact not be a compile time error but a runtime exception (nasty). It would be nice if you could say anything that is a primative (and with objects you can do this with extends ParentClass) but not with primatives. Primatives are only really in java at all because they are admittedly faster than their Object brothers (Integer, Double etc vs int, double etc). As such primatives are very much second class citizens in java – Richard Tingle Jul 01 '13 at 10:30
  • I think java's strength is that its promise based. A method signature makes a promise to accept certain classes and promises to return certain classes. A method that breaks that promise 95% of the time (and throws an exception) is not something i'd like to see – Richard Tingle Jul 01 '13 at 10:33
  • @Bathsheba I will admit though I have often wanted to write a function that will take either float or double arguments and return either a float of double so I can change from a float precision and double presision program without lots of difficult mighration from one to the other. This is something that is legitamately missing from java – Richard Tingle Jul 01 '13 at 10:46
1

6) Compiler doesn't like lhs[i] + rhs[i]. Presumably because it doesn't know the type of T, but C++ allows you do to this as it will not attempt to compile a template until it knows the type.

You could always write an interface with an .add(...) function and let T extend this interface. Then you could write lhs[i].add(rhs[i])

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
morrow
  • 174
  • 1
  • 15