Primitives in Generics
Reinier Zwitserloot
reinier at zwitserloot.com
Thu Jul 8 06:48:50 PDT 2010
It's quite relevant, because state-of-the-lambda suffers from a rather
serious problem, which is highlighted by a core use-case driving project
lambda: ParallelArray's Ops container with its 132 SAM types. This proposal
would solve the issue and reduce that set of 132 to 8.
If a JVM optimization can be proven to be trivial to implement (JRockit),
and fail to apply only in those cases where specialization wouldn't work
either, then I don't see how relying on this optimization is not sufficient.
Your idea is an intriguing one which would indeed drop the need for the
JRockit boxing elimination optimization, though I don't think it can work.
For example, the following 2 code samples would seem to be perfectly valid,
but as far as I can tell the end result will be a NoSuchMethodError because
the produced instance will not actually have the primitive version of the
method. How will the compiler stop you from doing this, and, even if it
does, how is a java programmer to know these snippets won't work?
Snippet #1: new ArrayList<int>().add(10);
and to show this problem cannot be remedied just by detecting such
situations and disallowing them:
Snippet #2:
public static List<T> createList(Class<T> type) { return new ArrayList<T>();
}
public void test() {
List<int> list = createList(int.class);
list.add(10);
}
--Reinier Zwitserloot
On Thu, Jul 8, 2010 at 9:42 AM, Gernot Neppert <mcnepp02 at googlemail.com>wrote:
> Reinier, I think your proposal is propably off-topic with regards to
> this mailing list, nevertheless I could not resist to respond ;-)
>
> I like the idea of making efficient use of generic classes with
> primitive type parameters possible. However, I'm worried that solely
> relying on a JVM optimization will not be sufficient. Wouldn't it be
> possible to gain efficiency on every VM if something along the
> following could be adopted:
>
> 1. Let's assume the existence of a generic interface
>
> L<T> {
> void add(T element);
> T get(int index);
> }
>
> 2. The declaration of a variable of type L<p> where p is one of the 8
> primitive types is possible.
> If the compiler encounters such a variable, it assumes that L<p>
> actually is equivalent to following 'extended' interface
>
> L'<P>
> {
> void add(P element);
> void add(p element);
> P get(int index);
> p get(int index);
> }
>
> where 'P' is the wrapper type corresponding to 'p'.
>
> 3. It would still remain illegal to declare an interface such as the
> above 'by hand', since overriding by return type is illegal unless the
> return types are covariant. However, the VM can cope with such
> overrides; and the compiler will encounter no ambiguities, as
> paragraph 4. will show.
>
> 4. With the assumptions made above, the following code would compile
> to the most efficient bytecode, invoking the primitive versions of
> 'add' and 'get':
>
> L<int> list;
> list.add(42);
> int value = list.get(0);
>
>
> 5. There has to be a means of instantiating objects of type L<p>. With
> the assumption made in 2., the solution is the same as with other
> abstract classes:
>
> A non-abstract class that implements L<p> for a primitive type p must
> implement those methods from the synthetic L'<p> that use the
> primitive type p, while the compiler will generate the necessary
> bridge methods with the wrapper type P:
>
> public class IntList implements L<int>
> {
> public void add(int element)
> {
> // efficient int-based implementation
> }
>
>
> public int get(int index)
> {
> // efficient int-based implementation.
> }
>
> }
>
> 6. The types L<P> and L<p> will be assignment compatible in only one
> direction: It will be possible to assign an instance of type L<int> to
> L<Integer>, but not vice versa.
>
> L<Integer> list1 = new IntList(); // OK
> L<int> list2 = new ArrayList<Integer>(); // Will not compile
>
> 7. If the assignment from L<P> to L<p> is forced through an unsafe
> cast, the attempt to invoke a method of L<p> using the primitive type
> p will result in a java.lang.NoSuchMethodException at runtime. This is
> comparable to the ClassCastException that can be thrown arbitrarily
> when unsafe casts are involved.
>
> L<int> list = (List<int>)(List)new ArrayList<Integer>();
> list.add(42); // Will throw NoSuchMethodException.
>
More information about the lambda-dev
mailing list