Primitives in Generics

Brian Goetz brian.goetz at oracle.com
Thu Jul 8 14:42:52 PDT 2010


Its worth noting that ParallelArray is really the *only* well-known bad case 
here.  Given the invasiveness to the language that function types represent, 
it seems a bad trade to take on such a big solution for a single ill-behaved 
library that some mad professor cooked up :)  :)  :)
                                           ^ Lots of smileys here!



On 7/8/2010 9:48 AM, Reinier Zwitserloot wrote:
> 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