リストのリストを型推論

List> ll = new ArrayList>();

というステートメントには、型が多すぎる。

    public class ListFactory
    {
public static<T> List<T> newInstance(T x, int ncopy)
{
    return new ArrayList<T>(Collections.nCopies(ncopy, x));
}
public static<T> List<T> newInstance()
{
    return new ArrayList<T>(Collections.<T>emptyList());
}

public static void main(String... args)
{
    List<List<String>> ll = ListFactory.newInstance(ListFactory.newInstance("a", 2), 3);
    //         ll.add(ListFactory.newInstance());
    List<String> l = ListFactory.newInstance();
    ll.add(l);
    System.out.println(ll);
}
    }

変数初期化のコンテキストが要求する型は完全な型だけれど、
メソッド引数のコンテキストが要求する型は実行時の型。
コメントアウトしたところの add は、
List
を要求していた。
なぜ?

いちおう考えてみた。

変数初期化ステートメントには完全な型情報(というか型パラメタ情報)があるのに対し、
メソッドシグネチャには実行時の型情報しかない。
クラスファイルしかないクラスのメソッドのシグネチャは、
クラスファイルに書かれている型情報しか持てないわけで、
そこにはコンパイル時にしか存在しない型パラメタの情報は含まれていない。

現状では、型を繰り返し書きたくない場合には、
適当な引数をつけて値のセットとかをすることにして、
そこから型推論してもらう、というのが無難か。

ほんとうは、バイトコードに型パラメタを書く
=マクロ展開式のジェネリクス
で、バイトコートレベルでコンテキストに完全な型パラメタの情報を
埋め込んだがいいような気がするけれど。

型パラメタ消去によるジェネリクスと、マクロ展開式のジェネリクスの得失は
よく分かっていない。
Java の場合は、互換性の問題もあり。