ageoff
ageoff

Reputation: 2828

Java Interfaces and Templates Confusion

I was reading through some questions on the differences between templates in some different programming languages. I understand that thanks mostly to this questions: What are the differences between Generics in C# and Java... and Templates in C++?. I did however get a little bit confused towards the end of the accepted answer when he starting talking about interfaces and when adding something. I understand the generals of interfaces mostly from this question: Explaining Interfaces to Students. I was still confused by what was stated in the question. So can someone better explain this last portion:

Because of this, the C++ compiler places no restrictions on what you can do with templates - basically any code you could write manually, you can get templates to write for you. The most obvious example is adding things:

In C# and Java, the generics system needs to know what methods are available for a class, and it needs to pass this down to the virtual machine. The only way to tell it this is by either hard-coding the actual class in, or using interfaces. For example:

string addNames( T first, T second ) { return first.Name() + second.Name(); }

That code won't compile in C# or Java, because it doesn't know that the type T actually provides a method called Name(). You have to tell it - in C# like this:

interface IHasName{ string Name(); }; string addNames( T first, T second ) where T : IHasName { .... }

And then you have to make sure the things you pass to addNames implement the IHasName interface and so on. The java syntax is different (), but it suffers from the same problems.

The 'classic' case for this problem is trying to write a function which does this

string addNames( T first, T second ) { return first + second; }

You can't actually write this code because there are no ways to declare an interface with the + method in it. You fail.

C++ suffers from none of these problems. The compiler doesn't care about passing types down to any VM's - if both your objects have a .Name() function, it will compile. If they don't, it won't. Simple.

I really want to understand the code in this answer as I was very confused how the .Name() method would work in the IHasName interface. Is someone has a better example that can further explain how interfaces can be used to add something like a name to a Person class or something else...

EDIT: I am more interested in the Java code.

Upvotes: 2

Views: 887

Answers (2)

Jorge_B
Jorge_B

Reputation: 9872

The reason that '+' compiles in C++ is that C++ templates are (and C++ experts PLEASE PLEASE forgive me for my clumsiness) like huge macros. It will wait until the template is instantiated to check if every operation is possible (still in compile time, as foo warned me in their comment).

For example this code:

#include "stdafx.h"

#include <stdio.h>

#include <vector>
#include <iostream>

template <class T> class adder {
public:
    adder();
    T add(T t1, T t2);
};


template <class T> adder<T>::adder() {}

template <class T> T adder<T>::add (T t1, T t2) {
        return t1 + t2;
}

using namespace std;

typedef vector<int> int_vector;


int _tmain(int argc, _TCHAR* argv[])
{

    adder<int_vector> vector_adder;
    int_vector v1;
    int_vector v2;

    v1.push_back(1);
    v1.push_back(2);

    v2.push_back(3);
    v2.push_back(4);
    v2.push_back(5);

    // will fail here, in compile time!
    int_vector v3 = vector_adder.add(v1, v2);

    for (int_vector::iterator it = v3.begin(); it != v3.end(); it++) {
        cout << *it;
    }

    return 0;
}

Will work perfectly until I try to add two vectors; in that moment, the C++ compiler will realize that there is no overload for the actual type I am using in the template. However, I could have defined some other operations in the template and the compiler would have not realized if I had not tried to add the actual types (then it will try to solve the macro). However something like adder<int> would perfectly work.

Java would not allow you to get to that point since it will allow no real operation with the generic types (it is great to define generic contains such as the classes under java.util.*, but little else). Your best shot is to go for a bounded type generic just like in the java documentation:

public class NaturalNumber<T extends Integer> {

    private T n;

    public NaturalNumber(T n)  { this.n = n; }

    public boolean isEven() {
        return n.intValue() % 2 == 0;
    }

    // ...
}

Here you can restrict the type of the generic to a certain super-class and there do some operations with it.

Upvotes: 2

zapl
zapl

Reputation: 63955

C++ Templates are very much different. But I don't understand why Java's generics can't do what you quote there.

interface IHasName {
    String getName();
}

class Person implements IHasName {
    private final String name;
    public Person(String name) {
        this.name = name;
    }

    @Override
    public String getName() {
        return name;
    }
}

class GenericUtility {
    public static <T extends IHasName> String addNames(T first, T second) {
        return first.getName() + ", " + second.getName();
    }
}

class Main {
    public static void main(String[] args) {
        Person first = new Person("Peter");
        IHasName second = new IHasName() {
            @Override
            public String getName() {
                return "John";
            }
        };
        String result = GenericUtility.addNames(first, second);
        System.out.println(result);
    }

}

Prints

Peter, John

And I would consider that as working as intended.

You can't actually write this code because there are no ways to declare an interface with the + method in it. You fail.

Java does not allow to override the + operator based on the parameter types. There is no fail here because you would have to take a different approach (that could be written as interface) in the first place.

C++ suffers from none of these problems. The compiler doesn't care about passing types down to any VM's - if both your objects have a .Name() function, it will compile. If they don't, it won't. Simple.

Neither will Java. If you declare that the generic parameter has to extend / implement a certain interface you'll get a compile time error in case a parameter does not.

Upvotes: 1

Related Questions