type safety in java 1.5 (bug or hole?)

Y

York Werres

Hi,

Gilad Bracha writes in chapter 7.3 of "Generics in the Java Programming
Language" this:

In particular, the language is designed to guarantee
that if your entire application has been compiled
without unchecked warnings using javac -source 1.5,
it is type safe.

But, believe it or not, my *very first* experiment at all with Java 1.5 was
this:

List<? super Number> list = new ArrayList<Serializable>();
list.add(new Double(0.0));
Integer theInt = (Integer) list.get(0);

I compiled it with "-source 1.5" (JDK 1.5.0 beta 1) and there were no
warnings at all. I then ran it and got a ClassCastException (as expected).

Why exactly is this called "type safe"?

Or to put the question another way: This is a bug, right?

My explanation attempt: The "? super Number" is a contra-variant bounded
wildcard which should be write-only. The compiler should not allow me to do
the "list.get(0)". The cast to Integer is ok, but calling the get is not
(because of it's return type).

Is this a known bug or do I have to report it somewhere?

BTW: This really is my very first experiment with Java generics and it
doesn't make me happy at all. What good are generics if they're not type
safe?

2004-05-17, York.
 
C

Chris Smith

York said:
Gilad Bracha writes in chapter 7.3 of "Generics in the Java Programming
Language" this:

In particular, the language is designed to guarantee
that if your entire application has been compiled
without unchecked warnings using javac -source 1.5,
it is type safe.

Right... but not if you explicitly do type-unsafe things. That sentence
is probably just fine if taken in context, but when you cast a reference
to something incompatible with the class of object it refers to, the
only thing that *can* happen is a ClassCastException!
But, believe it or not, my *very first* experiment at all with Java 1.5 was
this:

List<? super Number> list = new ArrayList<Serializable>();
list.add(new Double(0.0));
Integer theInt = (Integer) list.get(0);

The cast is the problem. Because there's no upper bound on the type of
the return value from List.get, the return type is effectively Object.
You could have said:

Object theNum = list.get(0);

And that would have been fine. But if you make your own further
assumptions after getting a number out of the list, and even add a cast
to insist to the compiler that it ignore your type-unsafe programming,
then you're no longer type-safe.
My explanation attempt: The "? super Number" is a contra-variant bounded
wildcard which should be write-only. The compiler should not allow me to do
the "list.get(0)".

The method is guaranteed to return a value, and since all objects in
Java are subclasses of Object, that value is guaranteed to be either
null or a reference to an Object. Hence, it can return a value of type
Object. There's no reason for the compiler to prohibit this call.
The cast to Integer is ok, but calling the get is not
(because of it's return type).

When you cast something, you're informing the compiler that even though
it can't prove that the value references an instance of the desired
class, *you* know that it does and the compiler should trust you.
You're essentially lying to the compiler; that reference doesn't point
to an Integer, even though you promised that it does.

Note that this has nothing to do with generics. You have a variable of
type Object, which refers to an object of class Double, and you're
trying to cast the reference to type Integer. That will always yield a
ClassCastException. The fact that you obtained the Object-typed
reference from a generic collection is irrelevant. It's your cast that
causes the ClassCastException.
BTW: This really is my very first experiment with Java generics and it
doesn't make me happy at all. What good are generics if they're not type
safe?

They are type-safe. However, if you write your own non-generic code
with arbitrary casting to other classes, then your non-generic code
obviously won't be type-safe. If you want type-safety, then don't cast.

--
www.designacourse.com
The Easiest Way to Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
 
J

John C. Bollinger

York said:
Hi,

Gilad Bracha writes in chapter 7.3 of "Generics in the Java Programming
Language" this:

In particular, the language is designed to guarantee
that if your entire application has been compiled
without unchecked warnings using javac -source 1.5,
it is type safe.

But, believe it or not, my *very first* experiment at all with Java 1.5 was
this:

List<? super Number> list = new ArrayList<Serializable>();
list.add(new Double(0.0));
Integer theInt = (Integer) list.get(0);

I compiled it with "-source 1.5" (JDK 1.5.0 beta 1) and there were no
warnings at all. I then ran it and got a ClassCastException (as expected).

Why exactly is this called "type safe"?

Or to put the question another way: This is a bug, right?

If "type safe" is supposed to mean "will never generate a
ClassCastException", and if Bracha's comments are an accurate expression
of part of the intent of generics, then I'd say yes, it's a bug.
My explanation attempt: The "? super Number" is a contra-variant bounded
wildcard which should be write-only. The compiler should not allow me to do
the "list.get(0)". The cast to Integer is ok, but calling the get is not
(because of it's return type).

No, I don't buy that. The compiler knows that all objects are instances
of Object, so it can safely assume that the return value of list.get(0)
is an Object, and it can therefore allow the call without a warning.
The declared type parameter for the specific list reference does not
allow a more specific assumption to be made, however, so the cast to
Integer should generate an unchecked warning.
Is this a known bug or do I have to report it somewhere?

I didn't see it in the bug database, but it seems like a pretty basic
situation, so I'm a bit surprised. The place to which you would report
such a bug is

http://developer.java.sun.com/developer/bugParade/index.jshtml

You need membership (free) in the Sun Developer Network to read the list
or post new bugs.
BTW: This really is my very first experiment with Java generics and it
doesn't make me happy at all. What good are generics if they're not type
safe?

Little good, I'd say, but
(1) They are intended to be type safe, and will be to the greatest
extent possible before Java 1.5 emerges from testing
(2) I think the use of generics in the example code obscures the fact
that the unsafe operation doesn't really involve generics at all --
rather, it involves a cast of a reference of type Object to a more
specific type (the former type is the result of the evaluation of a
genericly-typed expression, but the generics are out of the picture by
the time the cast comes around)
(3) Generics do provide a very handy syntax for some common things, and
even if they have type safety bugs, they aren't any worse than the
equivalent problems in non-generic code.


John Bollinger
(e-mail address removed)
 
M

Michael Borgwardt

York said:
Or to put the question another way: This is a bug, right?
No.

My explanation attempt: The "? super Number" is a contra-variant bounded
wildcard which should be write-only.

I really have no ideal what you mean with "write-only" in this context.
I have no experience with using generics, but the way I understand it is
that it ensures that the variable is only allowed to contain generic Lists
whose contents are Number or one of its superclasses. The result is that
the compiler will protest if you call put() on the variable with something
that cannot be put into the List object the variable refers to.
The compiler should not allow me to do
the "list.get(0)".

why not?
The cast to Integer is ok,

No, the cast to Integer is exactly what is NOT OK about your code.
 
P

Phillip Lord

York> Hi,

York> Gilad Bracha writes in chapter 7.3 of "Generics in the Java
York> Programming Language" this:

York> In particular, the language is designed to guarantee that if
York> your entire application has been compiled without unchecked
York> warnings using javac -source 1.5, it is type safe.

York> But, believe it or not, my *very first* experiment at all with
York> Java 1.5 was this:

York> List<? super Number> list = new ArrayList<Serializable>();
York> list.add(new Double(0.0)); Integer theInt = (Integer)
York> list.get(0);


Not over casts. The system has broken because you have explicitly told
it about this cast, claimed that it is safe and you wrong.

I'm a little surprised that it doesn't give you can't turn a warning
on, to tell you when a cast is being used though.

York> I compiled it with "-source 1.5" (JDK 1.5.0 beta 1) and there
York> were no warnings at all. I then ran it and got a
York> ClassCastException (as expected).

York> Why exactly is this called "type safe"?

York> Or to put the question another way: This is a bug, right?


I'm deeply unconvinced that this is a bug. The problem is that you are
reading a tutorial. By chapter 7.3 I suspect the author had assumed
that you are no longer inserting casts. I'd suggest that you read the
specification instead, which will tell you of the expected behaviour
when hitting a cast.



York> BTW: This really is my very first experiment with Java
York> generics and it doesn't make me happy at all. What good are
York> generics if they're not type safe?


Clearly java 1.5 has to support non type safe code, if it is to be
backward compatible. The question is whether the features allow to
leave out the cast and still program usefully. If you remove the cast
from 1.4, say, then writing any sort of code base would become nearly
impossible. The hope is that with generics this will no longer be
true.

Phil
 
C

Chris Uppal

York said:
List<? super Number> list = new ArrayList<Serializable>();

I'm not sure what you are trying to do here. Where does <Serializable> come
from ? Also, were you trying to make the declared type of list be a List of
Number ? I.e. a List that can (statically) be known to contain only instances
of Number and its subclasses ? If so then I think it should be declared:

List<Number> list = ...;

To be honest, I have no idea what the use of a wildcard in declaring a variable
is supposed to mean. The same goes for the use of a bound on the type (if I've
got the terminology right). I had thought they were only used in defining
generic classes and methods.

list.add(new Double(0.0));

OK, so now you have successfully added a Double to the list.

Integer theInt = (Integer) list.get(0);

If you had declared list to be a List<Number> then the static type of
list.get(0);
would be Number, and so the compiler would accept (statically) the cast from
Number to Integer. It would also require that cast. You've actually declared
it to be a wildcard which I'm assuming was a mistake. However, the /actual/
object returned by the expression is a Double, and Double is not assignable to
Integer and so the runtime cast must fail, exactly as if you'd written:

Number theNumber = new Double(0.0);
Integer theInteger = (Integer) theNumber;

or, even:

Object theObject = new Double(0.0);
Integer theInteger = (Integer) theObject;

which pass the compile-time type checks, but obviously must fail at runtime.

-- chris
 
Y

York Werres

They are type-safe. However, if you write your own non-generic code
with arbitrary casting to other classes, then your non-generic code
obviously won't be type-safe. If you want type-safety, then don't cast.

Yeah, I got that myself just a minute after posting (sorry): What had
mislead me for the moment (it was my first experiment with a Java 1.5
feature, after all) were Bracha's explicit and even highlighted words "the
language is designed to guarantee that if your entire application has been
compiled without unchecked warnings using javac -source 1.5, it is type
safe". There was absolutely no context that restricted this statement in the
paper to code completely without casts!

What I concluded (again: sorry that this was just *after* posting) was that
for making old code type safe, it is more important to first get rid of the
casts than to get rid of the compiler warnings. If the warnings are gone and
the casts are still there, you might still have the exceptions. But if the
casts are gone, so is most of the exception risk -- even if there are still
warnings:

List list1 = new ArrayList();
list1.add(new Double(0.0)); // <-- unsafe code (compiler issues warning)
Integer n1 = (Integer) list1.get(0); // <-- exception at runtime

List<? super Number> list2 = new ArrayList<Serializable>();
list2.add(new Double(0.0)); // <-- now safe code (no more warning)
Integer n2 = (Integer) list2.get(0); // <-- still exception at runtime

List<Integer> list3 = new ArrayList(); // <-- unsafe code (still a
warning)
list3.add(new Integer(0));
Integer n3 = list3.get(0); // <-- no more cast, no more exception

I had expected that the compiler warnings are there to guide the developer
towards type safety. And the explicit statement in Bracha's paper stongly
encouraged me to believe that.

The least I would have expected would be a compiler warning if the compiler
can infer that a cast is not type safe. Why are there no warnings for unsafe
casts? Is there a reason? After all, as seen above, it's the casts that must
be eliminated first. So there should be a compiler's help to *find* them.
This would also render the type safety statement in Bracha's paper true.

(Besides: I can tell my employer that, for the benefit of his/her company, I
have to get rid of the evil warnings. But I can not tell her that I have to
get rid of all the casts first -- just because I want to. She won't
unterstand why the greater threat to type safety, the casts, don't cause
warnings. They can't be that evil then, can't they?)

2004-05-17, York.
 
C

Chris Smith

Phillip said:
I'm deeply unconvinced that this is a bug. The problem is that you are
reading a tutorial. By chapter 7.3 I suspect the author had assumed
that you are no longer inserting casts. I'd suggest that you read the
specification instead, which will tell you of the expected behaviour
when hitting a cast.

I thought so, too... but the only specification I can find (for the JSR-
14 public review) is from 2001, and doesn't mention these wildcards as
far as I can see. Is there a better place to look?

--
www.designacourse.com
The Easiest Way to Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
 
R

Roedy Green

List<? super Number> list = new ArrayList<Serializable>();

I think it only works if you make the left and right side of that
identical. The compiler can't track what kind of collection you have
pointed to by a reference only the type of the reference. All it can
check is for line by line legality.
 
S

Scott Ellsworth

York Werres said:
(Besides: I can tell my employer that, for the benefit of his/her company, I
have to get rid of the evil warnings. But I can not tell her that I have to
get rid of all the casts first -- just because I want to. She won't
unterstand why the greater threat to type safety, the casts, don't cause
warnings. They can't be that evil then, can't they?)

I suspect that Eclipse and IDEA will have warnings for casts of typed
collections by the time 1.5 ships, if not before. See if you can grab
one of these tools, as then you will get warning messages sufficient to
convince your employer to let you fix them.

If nothing else, if your current code works, then it will not hurt it to
put in a type safe collection, which you can then do a Find Usages on to
walk down the tree.

Scott
 
P

Phillip Lord

York> The least I would have expected would be a compiler warning if
York> the compiler can infer that a cast is not type safe. Why are
York> there no warnings for unsafe casts? Is there a reason? After
York> all, as seen above, it's the casts that must be eliminated
York> first. So there should be a compiler's help to *find* them.
York> This would also render the type safety statement in Bracha's
York> paper true.


More or less by definition a cast is "unsafe". This is what it is
there for. Of course you can do things like

Frame f = new Frame();
Frame h = (Frame)f;

which is legal, but entirely pointless.


York> (Besides: I can tell my employer that, for the benefit of
York> his/her company, I have to get rid of the evil warnings. But I
York> can not tell her that I have to get rid of all the casts first
York> -- just because I want to. She won't unterstand why the
York> greater threat to type safety, the casts, don't cause
York> warnings. They can't be that evil then, can't they?)


I am surprised that there is no warning capability to tell you that
you are using casts. I would expect that you have to switch it on, as
the default behaviour would be programming without generics, which
means you have to have a cast. It seems odd to me though.

Phil
 
P

Phillip Lord

Chris> I thought so, too... but the only specification I can find
Chris> (for the JSR- 14 public review) is from 2001, and doesn't
Chris> mention these wildcards as far as I can see. Is there a
Chris> better place to look?


Bit depressing isn't it.

The best I could find is here

http://java.sun.com/developer/earlyAccess/adding_generics/

which includes a spec dated at 2003.

Phil
 
P

Phillip Lord

Roedy> On Mon, 17 May 2004 14:36:49 +0200, "York Werres"

Roedy> I think it only works if you make the left and right side of
Roedy> that identical. The compiler can't track what kind of
Roedy> collection you have pointed to by a reference only the type
Roedy> of the reference. All it can check is for line by line
Roedy> legality.



This should not be a problem.

The RHS says create an array list with elements of type
serializable. The LHS says treat this as a List (and ArrayList is a
kind of List) with elements of only things which are super classes of
Numbers (which is only Serializable).

I am a little surprised actually. I assumed that ? super Number would
include things of type Number, but perhaps it doesn't.

I have a suspicion that the generics stuff is going to cause a lot of
confusion when it comes out. They have done a lot of work to make it
as powerful as possible, given the constraints of being backward
compatible. The end result of this is that sometimes the results are a
little quirky or hard to understand, unless you have a good knowledge
of type theory (I don't!).

Phil
 
P

Phillip Lord

Roedy> On 18 May 2004 10:51:23 +0100, Phillip Lord

Roedy> The syntax is so ugly you'd think it was created by a Perl
Roedy> programmer.

Roedy> See http://mindprod.com/jgloss/generics.html

I don't think that they had a lot of choice to be honest, as they were
working within the constraints of a lot of the original grammar. For
example the use of extends and super to indicate upper and lower
bounds is because they did not want to create new keywords (which
might not be backward compatible).

But yes, I agree, it could look nicer.

Roedy> This does not bode well. The enums were much better done.

Roedy> see http://mindprod.com/jgloss/enum.html

Enums are much simpler, being essentially syntactic sugar. It's an
easier task.

Cheers

Phil
 
N

Neal Gafter

Type safety means that the dynamic type of every reference will be a subtype of
the static type of the variable that holds that reference. It implies that no
compiler-generated cast will fail.

You can still write your own casts to assert things that are false; such casts
can fail.
 
J

Jezuch

U¿ytkownik Chris Smith napisa³:
I thought so, too... but the only specification I can find (for the JSR-
14 public review) is from 2001, and doesn't mention these wildcards as
far as I can see. Is there a better place to look?

Maybe here:
http://today.java.net/pub/a/today/2004/01/15/wildcards.html
There's also
http://today.java.net/pub/a/today/2003/12/02/explorations.html

HTH :)
--
Ecce Jezuch
"I'm a search light soul they say
But I can't see it in the night
I'm only faking when I get it right
Cause I fell on black days" - C. Cornell
 
N

Neal Gafter

Chris said:
I thought so, too... but the only specification I can find (for the JSR-
14 public review) is from 2001, and doesn't mention these wildcards as
far as I can see. Is there a better place to look?

Adding Wildcards to the Java Programming Language. Mads Torgersen, Christian
Plesner Hansen, Erik Ernst, Peter von der Ahe, Gilad Bracha, and Neal Gafter. In
Proceedings of the 19th Annual ACM Symposium on Applied Computing, Nicosia, Cyprus.

http://www.gafter.com/~neal/wildcards.pdf
 
C

Chris Smith

Neal said:
Adding Wildcards to the Java Programming Language. Mads Torgersen, Christian
Plesner Hansen, Erik Ernst, Peter von der Ahe, Gilad Bracha, and Neal Gafter. In
Proceedings of the 19th Annual ACM Symposium on Applied Computing, Nicosia, Cyprus.

http://www.gafter.com/~neal/wildcards.pdf

Thanks, Neal. That should make for some interesting reading. I also
found the later version of the generics spec from within the early
access generics compiler.

--
www.designacourse.com
The Easiest Way to Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
 
J

John C. Bollinger

Neal said:
Type safety means that the dynamic type of every reference will be a
subtype of the static type of the variable that holds that reference.
It implies that no compiler-generated cast will fail.

You can still write your own casts to assert things that are false; such
casts can fail.

It would all the same be a nice complement to generics if the 1.5
compiler would indeed issue warnings about user-inserted casts that are
not provably correct. (I.e. those that the compiler cannot simply
ignore). That would give Bracha's comment (that started this confusion)
broad enough scope to no longer be confusing.


John Bollinger
(e-mail address removed)
 

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,769
Messages
2,569,578
Members
45,052
Latest member
LucyCarper

Latest Threads

Top