Why new T() is not possible in Java

People sometimes think that 'new T()' would be possible iff generics were reified. This is not true. Consider:

class Foo<T> {
T f = new T();
}

With erasure, you implement 'new T()' as 'new Object()', since Object is the bound of T. With reification, you instantiate an object whose class is the dynamic binding for T in 'this'. Either way, you must execute a no-args constructor.

But Foo doesn't require that a type bound to T (a.k.a. a witness of T) has a no-args constructor. 'new Foo<Integer>()' is perfectly legal, but Integer doesn't have a no-args constructor, so how is the instance initialization expression supposed to call 'new T()'? It can hardly make up a default value to pass to Integer's constructor.

'new T()' is fundamentally not possible in the context of nominal type bounds. (Or, if you prefer, in a context of separate compilation, since a global compilation could compute that 'new T()' is sound for all observed instantiations of Foo.) C# 2.0 introduced a structural type bound called the new() constraint to permit 'new T()'. However, they already had a need for interesting rules about which types can witness a type parameter, and in that context the "public parameterless constraint" is straightforward. C++ "concepts" go further in allowing a structural description of the types able to witness a type parameter.

Java is not going to get structural type bounds any time soon. Nominal type bounds of the form C&I (an intersection type) are complicated enough. Consequently, neither erasure nor reification alone can support 'new T()'.

Comments:

From time to time you hear a proposal about a 'class interface' concept: Such a thing would force classes to implement static methods with certain signatures.

The drive there seems to stem primarily from usage with Factory patterns, but you can co-opt it for this too - constructors have more in common with static methods than with instance methods from a type point of view.

Not saying I expect this will show up in java anytime soon, as the whole notion that static methods do not partake in the virtual lookup system will make it a fairly awkward concept. Still, something to think about.

Posted by Reinier Zwitserloot on February 14, 2008 at 05:24 PM PST #

Taken alone, as a change on top of Java 5/6, what problems for the typesystem would [T extends new T()] cause, before you consider more general cases?

Saying that C# has a messy typesystem isn't enough to show that Java wouldn't benefit from this.

Would reification make generic arrays work?

Posted by Ricky Clarkson on February 14, 2008 at 05:47 PM PST #

A different way of looking at it is that constructors are the forgotten bits of interfaces.

Another way of specifying this would be something like

public interface X {
X();
void doSomething();
}

class Foo<T extends X> {
T f = new T();
}

which would be useful in other contexts as well.

Posted by Noel Grandin on February 14, 2008 at 07:47 PM PST #

Reification could allow you to say new T[].

Getting an instance of T would also be possible if we assume T.class gives us the reified witness of T, using reflection: T.class.newInstance(). This would throw an exception if no no-arg constructor is available.

Posted by Peter Ahé on February 15, 2008 at 01:21 AM PST #

Reinier: FYI, Stefan Schulz has written about static interfaces ('contracts') and started an implementation at Kijaro - http://kijaro.dev.java.net. In addition constructor references from FCM closures are entirely compatible with method references, enabling constructors to be treated as just ordinary methods. This may demonstrate that we need to look at a package of language changes, rather than closures or reification in isolation.

Posted by Stephen Colebourne on February 15, 2008 at 07:25 AM PST #

Oops, the correct Kijaro link is http://kijaro.dev.java.net/

Posted by Stephen Colebourne on February 15, 2008 at 05:55 PM PST #

The idea of contracts might indeed help in some way. Although, it does not include constructors (yet?), one might contract factory methods to allow for instance creation.
Contracts alone do not help, though, as one would need a way to tell a Generic to contract to it. Maybe introducing an "extends static" in a generic definition similarily to the idea of "new T()":
<T extends static SomeFactoryInterface>
Should be part of the contracts proposal, I think.

Posted by Stefan Schulz on February 22, 2008 at 05:44 PM PST #

I think it's interesting to consider what uses such a thing might have in the language. Indeed, generic factories and singletons would be nice, but perhaps not nice enough to warrant a complex change to the type system; however, allowing constructors to be specified in interfaces (if there are no subtle implications of that; I'd have to look at the reasoning by which they were originally omitted) would be nice, as they'd come in useful in other situations too (I dimly remember gnashing my teeth about the lack of them back in my Java days, but I think I was doing something rather obscure with reflection at the time, and ended up having to use a factory I'd otherwise have been able to avoid).

Posted by Alaric Snell-Pym on March 01, 2008 at 11:59 PM PST #

Post a Comment:
Comments are closed for this entry.
About

Alex Buckley is the Specification Lead for the Java language and JVM at Oracle.

Search

Categories
Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today
Feeds