Will the new Generics mechanism still use runtime casting?

D

Dave Stallard

I have a question about the new Generics mechanism which articles I've
read have left me still a little uncertain about. Suppose you have
(say) a List whose elements are of class Foo. Objects of this type
would be declared as:

List<Foo> x = new List<Foo>();

Now suppose you do lookup or iteration:

Foo f = x.get(0);

With Generics, there is no longer a need to insert an explicit cast.
BUT, underneath the hood in the implementation, is there a still a cast
being performed at runtime in a statement like the one above? I
certainly hope not, since I know that runtime casts introduce a
performance penalty.

Dave
 
S

Skippy

With Generics, there is no longer a need to insert an explicit cast.
BUT, underneath the hood in the implementation, is there a still a cast
being performed at runtime in a statement like the one above?

Yep, generics are there to inform the compiler and ease the class-casting
pain, but the bytecode output is the same.
 
X

xarax

Skippy said:
Yep, generics are there to inform the compiler and ease the class-casting
pain, but the bytecode output is the same.

A properly implemented JVM can perform a cast or instanceof test
in constant time, regardless of the complexity of the inheritance
graph.

Don't worry about it. Computers exist for the convenience
of people, not vice versa. The big benefit of Generics is
that the compiler knows for certain that the cast will work
or not work. If the cast won't work, then you see a compile
error and can fix your code sooner than waiting for a runtime
exception.
 
P

Phillip Lord

xarax> A properly implemented JVM can perform a cast or instanceof
xarax> test in constant time, regardless of the complexity of the
xarax> inheritance graph.


Actually I don't think that it can, unless it pre-calculates a
transitive closure. Which it can't do in constant time.

xarax> Don't worry about it. Computers exist for the convenience of
xarax> people, not vice versa. The big benefit of Generics is that
xarax> the compiler knows for certain that the cast will work or not
xarax> work. If the cast won't work, then you see a compile error
xarax> and can fix your code sooner than waiting for a runtime
xarax> exception.


No. The "cast" can fail. And if it does you will get a
CastClassException where no Cast exists in code, only in byte code.

So for instance....

// generics working well...
List<Frame> frameList = new List<Frame>();
frameList.add( new Frame() );
Frame frame = frameList.get( 0 )


// this is an up cast. List<Frame> is a subtype of List...
List list = (List)frameList;
list.add( new Object() );
Object object = list.get( 1 );

//and this bit fails
frameList.get( 1 );


So in fact while generics mean that you don't have to put casts where
you used to, but they offer you few guarantees. At best I think they
should be considered something like more auto-boxing...that is more
syntactic sugar, than stronger type checking.

Phil
 
C

Chris Uppal

xarax said:
The big benefit of Generics is
that the compiler knows for certain that the cast will work
or not work.

Well, not exactly. It's more that the use of Generics persuades the compiler
that the cast *should* work, so it doesn't insist on whinging about it.
Whether it will *actually* work is another matter altogether.

-- chris
 
T

Tor Iver Wilhelmsen

The big benefit of Generics is that the compiler knows for certain
that the cast will work or not work. If the cast won't work, then
you see a compile error and can fix your code sooner than waiting
for a runtime exception.

Well, sort of. The specialized collection can still be cast to a
non-specialized one, much like you can cast away constness in C++.
 
M

Mark Thornton

Phillip said:
xarax> A properly implemented JVM can perform a cast or instanceof
xarax> test in constant time, regardless of the complexity of the
xarax> inheritance graph.


Actually I don't think that it can, unless it pre-calculates a
transitive closure. Which it can't do in constant time.

I tried measuring how long it actually takes with 1.4.2. A cast from
Object --> Integer appeared to take 0.5ns on my 3.06GHz P4. So whatever
they are doing it is astonishingly quick.

Mark Thornton
 
D

Dobromir Gaydarov

Take a look at Sun's presentation on Generics, pages 22 and 23 at
http://servlet.java.sun.com/javaone/conf/sessions/2733/0-sf2001.jsp (Sorry,
I could not copy the text here)

Based on that the following line from your sample

list.add( new Object() );

will generate (I quote) "compile-time unchecked warning".

I am not absolutely sure what this means.
If it was up to me I would like to see an error on the assignment

List list = (List)frameList;

making List<Frame> incompatible with List<Object>.

In fact why should List<A> be a subclass of List<B> if A is subclass of B?
Sure you need to be able to put objects of type A into List<B> and this does
not create any issues,
but what is the use of assigning the List<A> itself to variable of type
List<B>?

Regards,
Dobromir
 
C

Chris Uppal

Dobromir said:
In fact why should List<A> be a subclass of List<B> if A is subclass of B?
Sure you need to be able to put objects of type A into List<B> and this
does not create any issues,
but what is the use of assigning the List<A> itself to variable of type
List<B>?

Presumably for the same reasons (good or bad) as Java allows asssignment of a
String[] to an Object[] variable.

-- chris
 
N

Neal Gafter

Chris said:
Dobromir Gaydarov wrote:

In fact why should List<A> be a subclass of List<B> if A is subclass of B?
Sure you need to be able to put objects of type A into List<B> and this
does not create any issues,
but what is the use of assigning the List<A> itself to variable of type
List<B>?


Presumably for the same reasons (good or bad) as Java allows asssignment of a
String[] to an Object[] variable.

The reason was that generics were not available for expressing methods like
sort() that should operate on a variety of array types. That reason simply does
not apply in the presence of generics. The covariance of Java arrays is a flaw
in the type system not to be admired and imitated.

If A is a subclass of B, then both List<A> and List<B> are subtypes of
List<? extends B>
using the recently introduced "wildcards" notation.

-Neal
 
N

Neal Gafter

Casts to interface types are slower on many VMs.

Mark said:
I tried measuring how long it actually takes with 1.4.2. A cast from
Object --> Integer appeared to take 0.5ns on my 3.06GHz P4. So whatever
they are doing it is astonishingly quick.

Mark Thornton
 
N

Neal Gafter

Phillip said:
No. The "cast" can fail. And if it does you will get a
CastClassException where no Cast exists in code, only in byte code.

So for instance....

// generics working well...
List<Frame> frameList = new List<Frame>();
frameList.add( new Frame() );
Frame frame = frameList.get( 0 )


// this is an up cast. List<Frame> is a subtype of List...
List list = (List)frameList;
list.add( new Object() );
Object object = list.get( 1 );

//and this bit fails
frameList.get( 1 );


So in fact while generics mean that you don't have to put casts where
you used to, but they offer you few guarantees. At best I think they
should be considered something like more auto-boxing...that is more
syntactic sugar, than stronger type checking.

The Java compiler will give you a warning on the list.add() call. If your
entire application compiles with no such warnings, you are indeed guaranteed not
to have such failures at runtime.
 
P

Phillip Lord

Neal> The Java compiler will give you a warning on the list.add()
Neal> call. If your entire application compiles with no such
Neal> warnings, you are indeed guaranteed not to have such failures
Neal> at runtime.

Really? Thats interesting. This seems to be new to me. I guess I shall
have to re-read the spec.

While I can see how this would work, I wonder whether what you say is
true in general though. For instance.....


public void add( List list, Object o )
{
list.add( o );
}

will this throw a warning, as it can be called as...

List<Frame> list;
add( list, new Object() );

which causes the same difficulty. The general solution to this is to
make the type coercion go only in one direction. So List<Frame> can
become List, but it involves cloning, or never allowing you to treat
the object as List<Frame> again.

Phil
 
B

Bent C Dalager

The Java compiler will give you a warning on the list.add() call. If your

I assume it can only do this in the most trivial cases. What I am
worried about is when I write something along the lines of

List<Integer> list = new List<Integer>();
list.add(new Integer(3));
....
SomeClass.doCoolListThings((List) list);

where doCoolListThings() is a method I get from a third-party
library. It could merrily do something like list.add(new CoolThing())
and I don't see how the compiler could complain about that.

(is that an upcast? If so, would it get implicitly cast if I wrote
SomeClass.doCoolListThings(list);
when doCoolListThings is defined as
public void doCoolListThings(java.util.List list);
?)

Can someone explain why this generics implementation isn't just as
horrid as const_cast<> is in C++?

Cheers
Bent D
 
B

Bent C Dalager

It can because it sees that you pass a typed List to a method that
takes untyped List, and can warn you that bad things *could* happen to
it.

Well, yes, but that wasn't the warning I was looking for :)

So long as we don't have "const" methods, I will end up getting a load
of uninteresting warnings when calling library algorithms that I know
won't mutate my List.

The kind of warning I was looking for is when I actually try to use
the List in a way that violates its template parameters, i.e., when I
call List.add() with an unsuitable parameter type after having casted
the List. I am not looking for a warning when I cast the List to
something broader.

I don't believe the compiler can reliably give me the former and I am
not sure I want the latter.

Cheers
Bent D
 
T

Tor Iver Wilhelmsen

List<Integer> list = new List<Integer>();
list.add(new Integer(3));
...
SomeClass.doCoolListThings((List) list);

where doCoolListThings() is a method I get from a third-party
library. It could merrily do something like list.add(new CoolThing())
and I don't see how the compiler could complain about that.

It can because it sees that you pass a typed List to a method that
takes untyped List, and can warn you that bad things *could* happen to
it.
 
P

Phillip Lord

Tor> It can because it sees that you pass a typed List to a method
Tor> that takes untyped List, and can warn you that bad things
Tor> *could* happen to it.


Yes. But that means every time you want to pass a parametrically typed
object, to an method taking its erasure (or any other super class of
the parametrically typed object), you will get a warning.

As you will want to do this a lot, I suspect, the warning will be
relatively useless.

Phil
 
N

Neal Gafter

Phillip said:
While I can see how this would work, I wonder whether what you say is
true in general though. For instance.....


public void add( List list, Object o )
{
list.add( o );
}

will this throw a warning, as it can be called as...

Yes, it will.
List<Frame> list;
add( list, new Object() );

which causes the same difficulty. The general solution to this is to
make the type coercion go only in one direction. So List<Frame> can
become List, but it involves cloning, or never allowing you to treat
the object as List<Frame> again.

Right, not without a cast (which will provoke a warning).
 
C

Chris Uppal

Neal said:
If A is a subclass of B, then both List<A> and List<B> are subtypes of
List<? extends B>
using the recently introduced "wildcards" notation.

Is there a formal or informal, but complete, write-up of the *current* state of
Generics anywhere ?

I've seen stuff that's a few years old now, but nothing that is both recent and
complete enough for me to understand the new stuff fully*. E.g. this is the
first *I*'ve heard of the wildcard notation...

By "fully" I mean that I'd like to be able to:
- write Java code that uses the new stuff and understand
what it means (well, obviously!).
- understand the mechanisms well enough to see 'gotchas'
myself rather than be told about them by "experts".
- understand fully how the resulting code is presented
to the JVM -- I work mostly at bytecode/JNI level
so Java itself is rather less than half the story.

TIA

-- chris
 
P

Phillip Lord

Neal> Yes, it will.

This is not good. You will need to do this so often that the notion of
"compile without warning and you'll be safe" is lessened. It will be
hard to compile without warning.


Phil
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,763
Messages
2,569,562
Members
45,038
Latest member
OrderProperKetocapsules

Latest Threads

Top