Specification update: diamond and explicit generic constructor argument no longer supported

Dan Smith daniel.smith at oracle.com
Tue May 17 17:48:54 PDT 2011


This is a rule, called out in specifically in the JLS with some extended discussion, that javac was failing to conform to.  The change was to conform to the spec.

From JLS 3, 15.12.2.1:

> The clause above implies that a non-generic method may be potentially applicable to an invocation that supplies explicit type parameters. Indeed, it may turn out to be applicable. In such a case, the type parameters will simply be ignored.
> This rule stems from issues of compatibility and principles of substitutability. Since interfaces or superclasses may be generified independently of their subtypes, we may override a generic method with a non-generic one. However, the overriding (non-generic) method must be applicable to calls to the generic method, including calls that explicitly pass type parameters. Otherwise the subtype would not be substitutable for its generified supertype.

I'm not sure I believe that "the overriding (non-generic) method must be applicable to calls to the generic method"—I'm pretty sure this invariant is already violated in a number of ways elsewhere—but that was the rationale for the decision that was made when this was designed.

Resolution for constructors works "using the same rules as for method invocations" (15.9.3).  While clearly one could argue that the substitutability concerns above don't apply to constructors (nor to static or private methods...), the approach taken by the JLS was to consistently allow type arguments where none are needed.

—Dan


On May 17, 2011, at 3:50 PM, Joshua Bloch wrote:

> Maurizio,
> 
> Whoa, are you telling us that you folks intentionally made this legal?
> 
> *    Object o = new<String>Object();*
> 
> This code makes no sense!  Why should it be legal to pass a type parameter
> to a method or constructor that doesn't take one?  I dearly hope that I am
> missing something.
> 
>    What am I missing?
> 
>    Josh
> 
> On Tue, May 17, 2011 at 9:35 AM, Maurizio Cimadamore <
> maurizio.cimadamore at oracle.com> wrote:
> 
>> On 17/05/11 17:16, Anna Kozlova wrote:
>>> Hello,
>>> 
>>> may be here is not the best place to ask, but I am not sure whether the
>>> following was an intentional change or a bug?
>>> 
>>> {code}
>>>   Object o = new<String>Object();
>>> {code}
>> 
>>> Compiles in build 142 but didn't in jdk6 builds.
>> This is a deliberate change in javac in order to bring the compiler in
>> sync with the spec [1]
>>> The same question but this time with diamond operator: what if
>> constructor
>>> doesn't have type parameters but they are still passed?
>>> {code}
>>>   class Foo<T>  {
>>>       Foo(T t) {super();}
>>>   }
>>> {code}
>>> 
>>> Usage:
>>> {code}
>>>   new<Integer>  Foo<>("");
>>> {code}
>>> How compilation should fail?
>>> 
>> The combination of explicit constructor type-arguments and diamond
>> operator has been banned - the above code is not valid [2]
>> 
>> Thanks
>> Maurizio
>> 
>> [1] - http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5081782
>> [2] -
>> 
>> http://blogs.oracle.com/darcy/entry/project_coin_diamond_generic_constructors
>> 
>>> Thank you
>>> Anna Kozlova
>>> JetBrains Inc.
>>> http://www.jetbrains.com
>>> "Develop with pleasure!"
>>> 
>>> 
>>> -----Original Message-----
>>> From: coin-dev-bounces at openjdk.java.net
>>> [mailto:coin-dev-bounces at openjdk.java.net] On Behalf Of
>> joe.darcy at oracle.com
>>> Sent: Saturday, May 07, 2011 12:50 AM
>>> To: coin-dev at openjdk.java.net
>>> Subject: Specification update: diamond and explicit generic constructor
>>> argument no longer supported
>>> 
>>> Hello.
>>> 
>>> To address an issue in the specification, the JSR 334 expert group has
>>> decided to ban the combination of diamond together with explicit
>>> constructor type arguments. For background, a constructor can have two
>>> sets of type arguments. In a parameterized class, constructors can have
>>> type arguments corresponding to the class's type parameters. This is the
>>> common case and the type arguments appear to the right of the class name
>>> and "new" as in "new ArrayList<String>()". In addition, if a constructor
>>> declares its very own type parameters (which can be done whether or not
>>> the enclosing class is parameterized), then those type arguments appear
>>> between the "new" token and the class name as in "new<Integer>
>>> ConstructorWithTypeParameter(Integer.valueOf(42))".
>>> 
>>> As with generic methods, the type arguments of generic constructors are
>>> usually inferred and not explicitly passed. However, generic
>>> constructors are much less common than generic methods.
>>> 
>>> After the specification change, using diamond to infer the class type
>>> parameters but explicitly passing the constructor type parameters is
>>> forbidden. However, the other three combinations of explicitly passing
>>> type arguments versus inferring them are supported, as shown in the
>>> table below.
>>> 
>>> class Foo<T extends Number>  {
>>>       <S extends T>  Foo(S s) {super();}
>>> }
>>> 
>>> Class      C'tor        Supported   Example
>>> Explicit   Explicit     Yes         new<Integer>  Foo<Number>(null);
>>> Explicit   Inferred     Yes        new Foo<>(null);
>>> Inferred   Explicit     No         new<Integer>  Foo<>(null); // compile
>>> error
>>> Inferred   Inferred    Yes        new Foo<>(null);
>>> 
>>> The substitution that was used to formally describe the semantics of
>>> diamond did not fully propagate constraints if there was a typing
>>> relationship between the type parameters of the constructor and the type
>>> parameters of the class. Lifting the imposed restriction on the banned
>>> combination of explicit and inferred type arguments can be revisited in
>>> future work in the context of broader type inference getting added to
>>> the Java language.
>>> 
>>> Since generic constructors are so uncommon, adding this restriction
>>> about combining them with diamond should have little effect to most
>>> programs. For example, none of the uses of diamond in the JDK had to be
>>> updated as a result of this change. A changeset implementing this
>>> specification change has been pushed [1] and will appear in subsequent
>>> promoted builds of JDK 7.
>>> 
>>> -Joe
>>> 
>>> [1] http://hg.openjdk.java.net/jdk7/tl/langtools/rev/4caf17560ae0
>>> 
>>> 
>>> !DSPAM:35,4dc47a19236162090119686!
>>> 
>>> 
>> 
>> 
>> 
> 




More information about the coin-dev mailing list