Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is second level generics not possible in Java

Tags:

java

generics

Long story short: Why is the following not possible in Java?

public class Test<A<B>> {} // A and B both being generic parameters.

Note: I don't have any specific use case right now, rather I am just trying to understand why this is not allowed.

At first I thought because the compiler cannot assert if A can accept generics parameter because after compiling A, due to type erasure the generics won't be present anymore.

But, if that is the case, then we cannot use generics on any class at all. So I took out the byte code of a generic class and found that there is metadata to say it accepts generics.

public class com.Test<T> {
  public com.Test();
    Code:
       0: aload_0
       1: invokespecial #12                 // Method java/lang/Object."<init>":()V
       4: return
}

And I did a quick search and SO confirmed compiled code will have generics related metadata too

So why does the compiler not allow multilevel generics?

Will there be any problem in allowing it? Is it a limitation? or something else?

like image 204
Codebender Avatar asked Jul 25 '15 13:07

Codebender


2 Answers

Let's assume that this class was actually compiling:

public class Test<A<B>> { .. }

This implies that a proper instantiation of the class would be:

new Test<Class<Integer>>()
//or
new Test<List<String>>()

and the following wouldn't be correct (since the provided type-parameter is not generic):

new Test<String>();
//or
new Test<Object>();

However, a type-parameter should not be restricted for being generic or not - it should just hold some meta information about the type (and as it turns out, this is the type after type-erasure has taken place) with which it would be replaced.

Type-erasure itself can be another possible reason for not allowing such constructions. Let's again consider the above Test class was correctly defined and you had this:

new Test<Class<Integer>>();

When type-erasure happens, <A<B>> should be replaced with Class<Integer>, however, due to the erasure, we'd have only a Class (even though internally it would contain info about the Integer type) - expecting a Class<Integer>, but providing a Class should not be correct.

Thanks for the interesting question!

like image 182
Konstantin Yovkov Avatar answered Nov 10 '22 13:11

Konstantin Yovkov


Scala calls it higher kinded types. So it's definitely a feasible abstraction. Adding it to Java has — to my knowledge — never been seriously considered.

Sadly, I can't find any good introductory text to Scala's higher kinded types. The best I can find is the original paper Generics of a Higher Kind; here's its abstract:

With Java 5 and C# 2.0, first-order parametric polymorphism was introduced in mainstream object-oriented programming languages under the name of generics. Although the first-order variant of generics is very useful, it also imposes some restrictions: it is possible to abstract over a type, but the resulting type constructor cannot be abstracted over. This can lead to code duplication. We removed this restriction in Scala, by allowing type constructors as type parameters and abstract type members. This paper presents the design and implementation of the resulting type constructor polymorphism. Furthermore, we study how this feature interacts with existing object-oriented constructs, and show how it makes the language more expressive.

like image 22
Ben Schulz Avatar answered Nov 10 '22 12:11

Ben Schulz