先日、自分が書いた
に対する反応として、「Javaのようなまがい物のジェネリクスと比較するのは適切でない」「Javaのジェネリクスと比較するのは適切でない」(おそらくC#等の言語と比較して)といった コメントをいくつか見かけました(はてなブックマークコメントやツイッターなどで)。しかし、ここでは、そのような言説こそが適切でない、ということを言いたいです。なお、methane氏との 対話については既に終わったものなので、それとは関係ありません。
そもそも、Javaジェネリクスは、静的型付き関数型言語で既に一般的であったパラメータ多相をJavaに追加する目的で導入されました(C++テンプレートのようなものをJavaに追加するためだと思っている人がいるかもしれませんが、それは実態にあっていません)。実際、Java Genericsの前身のGeneric Javaのさらに前身であるPizzaの論文で、Martin Odersky*1は、PizzaはJavaにパラメータ多相(parametric polymorphism)などを導入するものであることを明言しています。
この、パラメータ多相という用語は、型理論の分野で広く使われている用語で、型によってコードをパラメータ化できるという性質を指します。重要なのは、パラメータ多相(ジェネリクスと同義)では、そのような、型によってパラメータ化されたコードを表現できて、なおかつその整合性を静的にチェックできるという点が本質であって、 型パラメータが実行時に取得できる とか、 特定の型引数に対して特殊化できる とかいった性質は、あくまで 実装方式 によって得られる追加のメリットであるということです。そして、追加のメリットがないというだけで、Javaジェネリクスが紛い物だとか主張するのは、JavaとC#、あるいはJavaとC++とかしか知らない人が自らの無理解を示しているに過ぎないし、噴飯モノの言説だということです。
また、実行時に型パラメータ情報を持ったり、特定の型パラメータに関して特殊化できるというのは便利ですが、ランタイムの実装を大幅に複雑化します(実行時にもパラメータ多相を扱えなければいけないので)。一方で、実行時に型パラメータ情報を持たなければ、ランタイムの型システムをある程度無視して言語の型システムを拡張しやすいです(Scalaが典型例)。
別の例としては、Javaは2016年に、型システムが健全でないことが証明されたり、型チェックが決定不能であることが証明されたりしていますが、ランタイムの型システムは別なので、これらの問題について、ランタイムが影響を受けることはありません。一方で、C#をはじめとした.NET言語では、言語の型システムとランタイムの型システムがかなり近いため、言語の型システムに欠陥が見つかると、それが直接ランタイムに影響を与えるおそれがあります。
このように、ジェネリクスの実装方式はそれぞれ得失があるので、どちらがいいとすぐ決めつけられるものではありません。両方の性質についてきちんと理解した上で、どちらの方式を支持するか決めるのはもちろんいいですが、その前に色々勉強すべきことがあると思います。