As some of you might know, my current project is a little toy programming language. As part of that, I'm doing some research into generics and the type inference of generic methods in particular.
There are three kind of quickie test cases I have, and ran for Java, C#, and C++:
// C# - VS2008
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1 {
public class a { }
public class b : a { }
public class c : a { }
class Program {
public static void Method<T>(T lhs, T rhs) {
Console.WriteLine(typeof(T).Name);
}
public static void ListMethod<T>(T lhs, List<T> rhs) {
Console.WriteLine(typeof(T).Name);
}
static void Main(string[] args) {
c C = new c();
b B = new b();
//Method(B, C); // failure.
List<a> foo = new List<a>();
ListMethod(B, foo);
}
}
}
// java - 1.6 NB6.1
// a,b,c included in other files
public class Main {
public static <T> void Method(T lhs, T rhs){
System.out.println(lhs.getClass().getName());
System.out.println(rhs.getClass().getName());
}
public static <T> void ListMethod(T lhs, ArrayList<T> rhs){
}
public static <T> void UnaryListMethod(ArrayList<T> rhs){
}
public static void main(String[] args) {
// TODO code application logic here
b B = new b();
c C = new c();
Method(B,C);
Method(B,new String());
ListMethod(B,new ArrayList<a>());
UnaryListMethod(new ArrayList<a>());
}
}
#include <iostream>
#include <vector>
template <class T> void Method(T *lhs, T *rhs){
T::foo();
}
class a{
public:
static void foo(){
std::cout << "A!\n";
}
};
class b:a{
public:
static void foo(){
std::cout << "B!\n";
}
};
class c:a{
public:
static void foo(){
std::cout << "C!\n";
}
};
template <class T> void ListMethod(std::vector<T> lhs, T rhs){
T::foo();
}
template <class T> void UnaryListMethod(std::vector<T> rhs){
T::foo();
}
int main(){
b B;
c C;
//Method(&B,&C); // failure.
std::vector<a> listA;
//ListMethod(listA,C); // failure.
UnaryListMethod(listA);
}
And the results are rather unusual.
C++ failed both combined inference tests, and passed only the one where the type was pulled from a parameter's template. Using straight types and not pointers for the method or pointer variables for the main produced similar failures.
C# failed the B,C inference, but somehow knew that B,List<A> would result in an A. (and seems to follow that behavior for Method if one is a subtype of the other). It too could pull from the generic bindings of its parameters.
And Java passed all 3 tests, though you couldn't really do much with T (though my java is poor, so I might be missing something).
Are there any similar tests that might expose quirks in the languages' implementations that I might find interesting? Any other languages' implementations (besides Haskell's) that are more interesting? And the real basis for the tests:
What do
you expect the behavior to be for Method(T,T) when called with two distinct types that share a common base type?