ジェネリックプログラミング
Adaの言語構文では、汎用体仮パラメータとして何を許容するか、精密に制約条件を課することができる。例えば実パラメータとしてはモジュラー型(任意の上限で巡回する符号なし整数型)のみを許容するように、仮パラメータとして指定することも可能である。さらには汎用体仮パラメータ間に一定の制約があるように規制することも可能である。例えば、
この例でArray_Typeには、Element_Typeに対応する特定のデータ型を要素とし、Index_Typeに対応する特定の離散型の部分型を添字とする配列型でなければならないという制約を課している。プログラマがこの汎用体をインスタンス化する際には、同制約を満足する配列型を実パラメタとして渡さなければならない。
構文の複雑さに難はあるものの、精密な制約が表現できることで、汎用体仮パラメータの全ては仕様部として完全に定義される。このため、コンパイラは汎用体本体がなくても汎用体をインスタンス化することができる(もちろん本体がないとリンクはできない)。
C++と異なってAdaでは暗黙的な特化による汎用体のインスタンス化を許さないため、全ての汎用体は明示的にインスタンス化することが必要である。この規則により以下のような結果が生じる。
コンパイラは共有ジェネリクス (shared generics) を実装できる。すなわち、ある汎用体のオブジェクトコードは全インスタンスで共有できる(もちろんプログラマが副プログラムのインライン化を要求しない限り)。
2004年、J2SE 5.0の一部としてJavaにジェネリクスが追加された。C++のテンプレートとは違い、Javaコードのジェネリクスはジェネリッククラスの1つのコンパイルされたバージョンだけを生成する。ジェネリックJavaクラスは型パラメータとしてオブジェクト型だけを利用できる(基本型は許されない)。従ってList<Integer>は正しいのに対してList<int>は正しくない。
Javaではジェネリクスはコンパイル時に型の正しさをチェックする。そしてジェネリック型情報は型消去 (type erasure) と呼ばれるプロセスを通じて除去され、親クラスの型情報だけが保持される。例えば、List<Integer>は全てのオブジェクトを保有できる非ジェネリックの(生の)Listに変換されるだろう。しかしながら、コンパイル時のチェックにより、コードが未チェックのコンパイルエラーを生成しない限り、型が正しいようにコードの出力が保証される。
このプロセスの典型的な副作用はジェネリック型の情報を実行時に参照できないことである。従って、実行時には、List<Integer>とList<String>が同じListクラスであることを示す。この副作用を緩和するひとつの方法はCollectionの宣言を修飾するJavaのCollections.checkedList(List<E>, Class<E>)メソッドを利用して、実行時に型付けされたCollectionの不正利用(例えば不適切な型の挿入)をチェックすることによるものである。これは旧式のコードとジェネリクスを利用するコードを共存運用したい場合の状況で役立つ。
C++やC#のように、Javaはネストされたジェネリック型を定義できる。従って、例えばList<Map<Integer, String>>は有効な型である。