participate


Generics - ArrayList.toArray()
<<   Back to Forum  |   Give us Feedback
This topic has 13 replies on 1 page.
krausest1
Posts:124
Registered: 1/25/00
ArrayList.toArray()   
Jun 9, 2003 9:15 AM

 
Hi,

I thought the following code should work fine now:
ArrayList<Integer> v=new ArrayList<Integer>();
v.add(new Integer(5));
Integer[=] intArray=v.toArray();
System.out.println(intArray[0]);


But it fails at the call to toArray with a class cast exception. Shouldn't happen, should it?

If it shouldn't (and I think so, 'cause the overview pdf shows it on page 25) how is it handled internally? The important line in toArray is E[=] result = new E[size];
What's left of this line after type erasure? (If E is erased to object then I understand where the class cast exception comes from)

Thanks,
Stefan
 
lerzeel
Posts:33
Registered: 6/29/98
Re: ArrayList.toArray()   
Jun 11, 2003 3:08 AM (reply 1 of 13)  (In reply to original post )

 
The slides do indeed show this. So I guess the slides are wrong then ? If they are, what should be the correct syntax ?
 
cplesner
Posts:17
Registered: 6/1/03
Re: ArrayList.toArray()   
Jun 11, 2003 12:13 PM (reply 2 of 13)  (In reply to original post )

 
What's left of this line after type erasure? (If E is
erased to object then I understand where the class
cast exception comes from)

That's exactly the problem: "new E[...]" gives an Object[] if E is a type variable. We're aware of the problem and are currently looking at a number of different solutions to it, one of which is disallowing "new E[...]".

-- Christian
 
krausest1
Posts:124
Registered: 1/25/00
Re: ArrayList.toArray()   
Jun 11, 2003 12:51 PM (reply 3 of 13)  (In reply to #2 )

 
one of which is disallowing "new E[...]".

I wholeheartedly hope there will be another solution. Disallowing seems to lessen usability substantially and passing the class to instantiate (via reflection similar to what is done in toArray(E[-] a)) is pretty ugly for it's too obvious that it's just a workaround.

Yours,
Stefan
 
YATArchivist
Posts:4,906
Registered: 23/07/02
Re: ArrayList.toArray()   
Jun 11, 2003 3:02 PM (reply 4 of 13)  (In reply to #3 )

 
In the earlier prototypes, compatibility of generic classes with older VMs ruled out making the VM contain information about the runtime type parameters. Since it appears -source 1.5 will produce classes which don't work with older VMs anyway, that presumably isn't an issue, so is there any reason why the VM can't know at runtime what E is?
 
schapel
Posts:2,586
Registered: 6/22/99
Re: ArrayList.toArray()   
Jun 11, 2003 3:36 PM (reply 5 of 13)  (In reply to #4 )

 
In the earlier prototypes, compatibility of generic
classes with older VMs ruled out making the VM contain
information about the runtime type parameters. Since
it appears -source 1.5 will produce classes which
don't work with older VMs anyway, that presumably
isn't an issue, so is there any reason why the VM
can't know at runtime what E is?

Sure, it would require significant changes to the JVM. As it is, JSR14 still does not call for any changes to the JVM, even though -source 1.5 implies -target 1.5 for javac.
 
brucechapman
Posts:683
Registered: 11/24/98
Re: ArrayList.toArray()   
Jun 11, 2003 7:34 PM (reply 6 of 13)  (In reply to #2 )

 
What's left of this line after type erasure? (If E is
erased to object then I understand where the class
cast exception comes from)

That's exactly the problem: "new E[...]" gives an
Object[] if E is a type variable. We're aware of the
problem and are currently looking at a number of
different solutions to it, one of which is disallowing
"new E[...]".

-- Christian

Christian,

You don't have to disallow it

A possible solution was hinted at here http://forum.java.sun.com/thread.jsp?forum=316&thread=359061#1514591
but the need is now greater.

To reiterate (and update to Generics EA release 2)

For the rare cases where type parameters need to be known inside an instance, we add a "special" constructor signature, that the compiler can recognise, and at runtime this constructor is then passed the reflected type parameters from the "new" expression.

JSR175 might be usefully employed to indicate to the compiler that runtime type parameters should be passed.
The (possible) advent of the varargs stuff, suggests another syntax using a similar ... .

This in essence adds syntactic sugar to the obvious solution, which is to pass a Class or Type in the constructor
new ArrayList<String>(String.class)


so new ArrayList<String>.toArray() can return a String[] not an Object[].

Same could be applied for generic methods.

Some examples
new Widget<String>(5)

could be made to invoke a constructor with one of the following signatures (if it existed), or the normal Widget(int size) one otherwise.

Possible Type parameter aware constructor signatures / syntax

Widget(Type[] typeargs,int size){}
//familiar but maybe problematic

or

Widget(Type[] typeargs...,int size) {}
//maybe ambiguous in case when no "normal" parameters

or

Widget(Type[] ...typeargs,int size) {}
// ...name means type parameter args and
// type must be "Type[]", must be 1st parameter.
// name... means normal var args and must be last.

or

Widget(Type[],int size) @java.lang.TypeParameterAware() {}
// uses probable JSR175 syntax (as far as I can glean)!!

or

Widget<typeargs>(int size) {}
// but doesn't specify the Type of the parameter typeargs
// but the type will always be Type[]
or

Widget<Type[] typeargs>(int size) {}
// possibly the best

or

Widget<Type[] typeargs...>(int size) {}
// for consistency because it is matched by a syntactic list of types
// not by a Type[] expression.
[/code]

and similarly for parametric methods

/* non generic code calls this one */
public Object[] dongle(int size) {
    return new Object[size];
}
 
/** type safe generic array constructor*/
public <A>  A[] dongle<Type[] typeargs>(int size) {
    return java.lang.reflect.Array.newInstance(typeargs[0],size);
}


I think all the above syntaxes could possibly work in terms of parsing (but I'm no expert). However I like the ...name and <Type[] name> syntaxes the most.

When the compiler is resolving which constructor to invoke, preference would be given to one expecting type parameters, and in the absence of one of those (which would in fact be the normal case), then match as per currently.

This will yield run time Type knowledge when required (and the toArray() problem in this thread is a case in point), without imposing runtime overhead on the majority of generic classes which don't need it.

Bruce
 
YATArchivist
Posts:4,906
Registered: 23/07/02
Re: ArrayList.toArray()   
Jun 12, 2003 4:18 AM (reply 7 of 13)  (In reply to #5 )

 
Sure, it would require significant changes to the JVM. As it is, JSR14 still does not call for
any changes to the JVM, even though -source 1.5 implies -target 1.5 for javac.

My point was that since JSR14 will be shipped together with other language changes which require VM changes, "It would require changes to the VM" is not in itself an argument against it. ISTM the argument should be moved to "Are the changes to the VM worth it for the benefits it would give?"
 
schapel
Posts:2,586
Registered: 6/22/99
Re: ArrayList.toArray()   
Jun 12, 2003 6:59 AM (reply 8 of 13)  (In reply to #7 )

 
My point was that since JSR14 will be shipped together
with other language changes which require VM changes,
"It would require changes to the VM" is not in itself
an argument against it. ISTM the argument should be
moved to "Are the changes to the VM worth it for the
benefits it would give?"

What changes to the JVM are needed for JDK 1.5?
 
gafter
Posts:669
Registered: 6/25/98
Re: ArrayList.toArray()   
Jun 12, 2003 7:11 AM (reply 9 of 13)  (In reply to #7 )

 
My point was that since JSR14 will be shipped together
with other language changes which require VM changes,
"It would require changes to the VM" is not in itself
an argument against it. ISTM the argument should be
moved to "Are the changes to the VM worth it for the
benefits it would give?"

The question is really "Can we design an implement a
compatible language extension that supports this in the
next two months?"

We don't believe this is possible, even given much more
time. All of the options for making type parameters
available at runtime appear to involve compatibility
problems.
 
gafter
Posts:669
Registered: 6/25/98
Re: ArrayList.toArray()   
Jun 12, 2003 7:13 AM (reply 10 of 13)  (In reply to #8 )

 
What changes to the JVM are needed for JDK 1.5?

New verifier tables based on CLDC.

Two previously unused flag bits used for enums, varargs.

New support for class literals.

New support for synthetic names.

A number of new class file attributes to support the language features.
 
brucechapman
Posts:683
Registered: 11/24/98
Re: ArrayList.toArray()   
Jun 12, 2003 3:25 PM (reply 11 of 13)  (In reply to #9 )

 

The question is really "Can we design an implement a
compatible language extension that supports this in the
next two months?"

We don't believe this is possible, even given much more
time. All of the options for making type parameters
available at runtime appear to involve compatibility
problems.



What compatibility problems are there in the "on demand" type parameters passing mechanism suggested by my post (reply 6) above?

where (for one example of the syntax) you have a constructor declared
    ArrayList<Type[] typeargs>() {
        runtimeType=typeargs[0];
    }

which generates equivalent bytecode to that generated by
    // "runtime typed" constructor
    ArrayList(Type[] typeargs) {
        runtimeType=typeargs[0];
    }
    // synthetic "bridge" constructor
    ArrayList() {
         this(new Type[] { Object.class });
    }


except the "runtime typed" constructor has yet another bytecode flag to mark it as a "runtime typed" constructor. (You seem to be adding quite a few more flags in 1.5 so 1 more won't hurt at this stage will it?)

And at the point where it is called..
    new ArrayList<String>();

generates the same bytecode as
    new ArrayList<String>(new Type[] { String.class});


Because the compiler matches the invocation to the "runtime typed" constructor in preference to another with no arguments.

I know this is only a suggestion and it needs more work, but it is really only syntactic sugar for declaring a Type argument explicitly on the constructors for things that need runtime type info, and then the caller tells the constructor the type. It solves all the specific problems where we need runtime type info in the collection classes. It provides no overhead where we don't.

I can't see any problems. Can anyone else?

Bruce
 
gafter
Posts:669
Registered: 6/25/98
Re: ArrayList.toArray()   
Jun 18, 2003 8:58 PM (reply 12 of 13)  (In reply to #6 )

 
You don't have to disallow it

A possible solution was hinted at here
http://forum.java.sun.com/thread.jsp?forum=316&thread=3
9061#1514591
but the need is now greater.

To reiterate (and update to Generics EA release 2)

For the rare cases where type parameters need to be
known inside an instance, we add a "special"
constructor signature, that the compiler can
recognise, and at runtime this constructor is then
passed the reflected type parameters from the "new"
expression.

Sorry, that's just not compatible. The signature of a
method may not depend on the implementation of the bodies
of other methods in the class. Separation of interface
and implementation.
 
brianstoler
Posts:6
Registered: 9/19/98
Re: ArrayList.toArray()   
Jun 18, 2003 9:32 PM (reply 13 of 13)  (In reply to original post )

 
Just another random mention of the fact that NextGen, a research extension of generic Java developed at Rice University (http://www.cs.rice.edu/~javaplt/nextgen/doc), supports new E[] and any other runtime operation based on the instantiated type parameters. NextGen, which was co-designed by Guy Steele of Sun and proposed in a 1998 paper (http://citeseer.nj.nec.com/cartwright98compatible.html), is an upwardly compatible extension of GJ/JSR-14's generics (though it doesn't handle variance yet, I'm pretty sure). It thus could be the basis of a future extension of the language (JDK 2.0?).

Plus, NextGen, as opposed to the proposals here that involve passing the type parameters to the constructor, does not require storage space per instance for the type parameters. And it need not require JVM changes (as the current implementation does not.)

I'm not sure about the details of the current implementation, but from a design view it can support any operation at all involving the type parameter, even new E() once some form of constructor interface is worked out.

(I worked on NextGen a bit as a graduate student and have recently been bringing it up on this forum as it solves a lot of the common problems people bring up about GJ.)

-brian
 
This topic has 13 replies on 1 page.
Back to Forum
 
Read the Developer Forums Code of Conduct

Click to email this message Email this Topic

Edit this Topic
  
 
 
Forums Statistics
    Users Online : 25
  • Guests : 136

About Sun forums
  • Sun Forums is a large collection of user generated discussions. It is here to help you ask questions, find answers, and participate in discussions.

    Check out our guide on Getting started with Sun Forums for a full walkthrough of how to best leverage the benefits of this community.

Powered by Jive Forums