I just did a rebuild, and got 100 "Type safety" warnings. It used
to be warning-free.
My options seem to be:
1. Modify the source code to use generics, spending time making changes
that are not really relevant to my current project.
2. Live with the warnings, and the consequential risk that I'll miss a
warning that does mean something.
3. Go back to JDK 1.4, and not use e.g. generics in any new code.
4. Something else? If so, what?
Has anyone found a good solution to this problem? If not, any advice on
which less-than-desirable compromise to choose?
Thanks,
Patricia
But this will prevent the use of generics in new code.
In order to be able to use generics in new code, warnings can be
suppressed using annotations:
@SuppressWarnings("unchecked")
see:
http://java.sun.com/docs/books/tutorial/java/javaOO/annotations.html
Patricia,
If the company or persons using the project has *no issue* in using JDK
1.5, I would go ahead and fix the type safety warnings because:
1. a year or more later, the code will be easier to maintain.
2. generics are generally a good idea that helps the programmer avoid
future type casting mistakes. That's worth a lot.
3. you may spot a yet undiscovered bug.
Cheers,
Missaka
It's part of my academic research, so I am, in effect, my own customer.
However, I'm also my own project manager, responsible for prioritizing
changes, and a firm believer in "If it ain't broke, don't fix it.".
Patricia
-Xlint:unchecked will shut 'em up, however,
there's a good chance you can simplify the code (and subsequent maintenance)
by getting rid of explicit casts and adding foreach loops,
unless you haven't learned anything in the last 12 months, you're sure to
find a few things in your code you'll want to improve. (Of course, whether
that's worth your time is another question.)
Dima
--
Backwards compatibility is either a pun or an oxymoron. -- PGN
I would do something like the following:
First, characterize the warnings 1.5 adds to previously warning-free code.
Next, create a filter that removes them from the javac output, and use that
filter to compile your code. If, at some future date, you want to start
using generics and will want to see the warnings, add a comment like
/** No warnings in JDK 1.4 */
to the code you *won't* be genericizing, and filter results only for files
that don't contain that comment. (Alternatively, make this a private field
instead of a comment, if your filter is written in Java and it's easier to
use reflection on the class file than to grep the source file.)
Almost invariably, when I reread code I find things I could do better.
The decision about whether to make the change depends on circumstances.
Patricia
> I'm picking up a project I last worked on about a year, and one JDK
> version, ago. It makes extensive use of java.util collections.
>
> I just did a rebuild, and got 100 "Type safety" warnings. It used
> to be warning-free.
I can't offer alternative technical solutions. I doubt if there are any
(though Mike's ingenious idea comes close). Welcome to the wonderful world of
generics make-work !
Is it possible to split your stuff up so that you can compile some
sub-components with 1.4 settings, while continuing to work on other parts with
a 1.5 compiler ?
If not, or to the extent that is is not, then I think I'd just [sigh deeply
and] accept the hit. Better to get it over with now, rather than having it
hanging around irritating me every time I think about it... It'd be a chance
to do some code-cleaning too, so it might not be a /total/ waste of time.
This is what we get for using a language with a fashion-lead design process.
-- chris
>
> 3. Go back to JDK 1.4, and not use e.g. generics in any new code.
>
> Thanks,
>
> Patricia
Whereas I like Chris's oh-so deep sighing, I would ask what's wrong with
sticking with 1.4? Are there particular features you require in 1.5 that
are not in 1.4?
1.4 is neither a second-best nor an out-dated version of the language
(older, yes, out-dated, no). Generics-lovers will flap hands, roll eyes,
mince around, and squeal, "But it's sssssssssssssooooooooo type-unsafe!"
If you're constantly getting ClassCastExceptions because you're
repeatedly pulling the wrong class from your collections, then move to
1.5 and generics-up; but if you've programmed in Java for more than 6
months, you'll probably get one of those exceptions per year, and it'll
take you somewhere in the region of ... oh, say five seconds to correct it.
And what happens when Java 1.6 (ok, ok, Java 6) comes out? Will you
enter zombie-mode and slowly, awkwardly update all your code to be
1.6-specific (all the while moaning, "Brains ...")?
Oh, wait! Hang on! I forgot: in Java 1.5 you can use foreach. Forget
everything I said; upgrade to 1.5 and change all your for-loops to
foreaches. That'll make it all worthwhile!!
(And if you're wondering whether that's sarcasm, then you really do need
to upgrade to 1.5.)
(Sarcasm: 2, Common Sense: 0)
--
www.EdmundKirwan.com - Home of The Fractal Class Composition.
Download Fractality, free Java code analyzer:
www.EdmundKirwan.com/servlet/fractal/frac-page130.html
Fortunately, I use Eclipse. I went into project properties, and found,
under "Java Compiler", "Errors/Warnings". It supplies separate control
for a series of conditions. J2SE 5.0 gets its very own tab. Changing
"Unchecked generic type operation" from "Warning" to "Ignore" got me
back to a warning-free compilation.
It seems sufficiently specific that it is unlikely to mask any warning I
would care about, unless/until I decide to get on the generic bandwagon.
It also has options in the other direction. I'm not sure I really like
the automatic boxing/unboxing feature. Eclipse has an option to turn
that into a warning or error.
NICE Eclipse.
Thanks to everyone for their suggestions, and to the Eclipse developers.
Patricia
> Fortunately, I use Eclipse. I went into project properties, and found,
> under "Java Compiler", "Errors/Warnings". It supplies separate control
> for a series of conditions. J2SE 5.0 gets its very own tab. Changing
> "Unchecked generic type operation" from "Warning" to "Ignore" got me
> back to a warning-free compilation.
Ah, that was the clever technical solution I couldn't think of -- switch to a
different compiler ;-)
-- chris
Can you show some of the statements that cause warnings? We'll be in the
same state before long (code we don't want to touch that we'll be compiling
under 1.5) and I'd like to know what to watch out for.
Sure. Here's a typical case:
Type safety: The method get(int) belongs to the raw type List.
References to generic type List<E> should be parameterized
The source code line is:
Shop s = (Shop) allShops.get(j);
where allShops is declared as:
private static List allShops = new ArrayList();
Here's another form:
Type safety: The expression of type FileTimes.TimeComparator needs
unchecked conversion to conform to Comparator<? super T>
The source code line is:
Collections.sort(files, new TimeComparator());
Unfortunately, I don't see anything that can be done to make a program
using java.util collections work in 1.4 and also be warning-clean in 1.5.
Patricia
What I don't understand ...
OK, *among* the things I don't understand is why the raw type can't be
defined as the moral equivalent of TYPE<Object> (in a type which so declares
it, not for all types). That would be correct for the java.util.collections
generics, at least, and would remove this sort of silly warning. You' still
get a warning when you passed, say, List<String> to a method that expects a
raw List, but that's a sensible warning, and comes from mixing 1.4 and 1.5
code.
This happened to us. We had this big project that used lots of
collections back when 1.4 was the latest version of Java. Our project lead
is a big fan of using the latest and greastest versions of everything, so
when Java 1.5 came out, we immediately switched over, yielding lots of
warnings.
We generally ignored the warnings for the most part. When we had to
revisit and update a given class, that's when we'd spend the time to
actually update the code to use generics.
Over the process of slowly converting the code, we've uncovered a bug.
Basically, one part of the code thought it was dealing with a vector of
Customer (i.e. Vector<Customer>), but it was actually a Vector<String>
representing customer IDs.
- Oliver
There's arguments for it being "defined as the moral equivalent of"
(DATMEO) TYPE<Object>, and there's arguments for it being DATMEO TYPE<?>.
The two have different semantics. Probably the designers argued back and
forth between these two DATMEO interpretations, until they finally threw up
their hands and decided that raw types are "neither", that they'll be
referred to as "raw", and that we'll put warnings to get the programmers to
specify whether they mean TYPE<Object>, TYPE<?>, or something else
altogether.
- Oliver
> Over the process of slowly converting the code, we've uncovered a bug.
> Basically, one part of the code thought it was dealing with a vector of
> Customer (i.e. Vector<Customer>), but it was actually a Vector<String>
> representing customer IDs.
Wow! An actual, real live, bug found by generics -- I'm impressed.
(BTW, out of real curiosity, about how many warnings were /not/ indicators of
bugs ? Also, how did a confusion between Customer and String get through
testing, did two bugs cancel out, or something ?)
-- chris
All the others. The figure was in the low 3 digits (200? 300?)
> Also, how did a confusion between Customer and String get through
> testing, did two bugs cancel out, or something ?)
I think that part of the code never actually got executed. It was part
of a GUI whose window wasn't ever made setVisible(true) yet, since the
features were still experimental and in early development.
- Oliver
>Wow! An actual, real live, bug found by generics -- I'm impressed.
Perhaps the most frustrating Java programming assignment I ever did
was a classified ad system. I was handed code with hundreds of
collections all with Generic Map type, along with collection
assignment Had the code been done with Generics, it would have been a
snap.. Tracking down just what was supposed to go in each collection
was a nightmare.
On top of that there was the matter of null pointers. Where are they
valid and where do you need empty strings?
--
Canadian Mind Products, Roedy Green.
http://mindprod.com Java custom programming, consulting and coaching.
Off and on, I've been playing with the idea that there could be two kinds of
references in Java: those that can contain "null" as a value and those that
can't. Assigning null to a non-nullable reference would be illegal.
Assigning a nullable reference to a non-nullable one would require a cast
and might result in an NPE then and there, so that the NPE points to the
logical error, rather than occurring later when some perfectly innocent code
trips over the null pointer.
>
>Off and on, I've been playing with the idea that there could be two kinds of
>references in Java: those that can contain "null" as a value and those that
>can't. Assigning null to a non-nullable reference would be illegal.
>Assigning a nullable reference to a non-nullable one would require a cast
>and might result in an NPE then and there, so that the NPE points to the
>logical error, rather than occurring later when some perfectly innocent code
>trips over the null pointer.
I have had similar thoughts. I thought about using javadoc to at
least document which references are nullable.
Nice does that. It gets a bit difficult with constructors - how do you
know if a member variable has been initialised yet? And then there's
threads...
Tom Hawtin
--
Unemployed English Java programmer
http://jroller.com/page/tackline/
> And then there's threads...
I suppose you'd need to guarantee that objects gets flushed after
construction. Or just accept that odd behavior can result from
unsychronized access.
The one I can't see a good solution for is arrays. A newly constrcuted
array is full of null pointers, and you can initialize all of the members
perhaps 10% of the time. I think you have to accept that
~Object o = arr[i]; // proposed syntax for non-nullable references
alwyas needs to be checked.
Constructors can call methods before final variables are set. Certainly
the super constructor will have been called.
> The one I can't see a good solution for is arrays. A newly constrcuted
> array is full of null pointers, and you can initialize all of the members
> perhaps 10% of the time. I think you have to accept that
Just insist on using collections instead...
You are eluding to the formal invalidation of "OO as we know it" under a
given axiom (which I believe you are assuming). Care to continue the logic?
It's quite interesting - for myself and a few other interested parties at
least. Of course, like most religions, it's difficult for its subscribers to
swallow - but that's all part of the fun :) I can refer you to other
interested people if you like.
--
Tony Morris
http://tmorris.net/
The super constructor can't see the variables defined at the level of
"this". You're right that methods called from a constructor will have to be
careful about the state of the object being constrcted, but that's already
true.
My point about finals was probably unclear. I meant that the compiler
already knows how to check than finals get set from every constructor; they
can equally well check that any non-nullable field gets set from every
constrcutor.
>
>> The one I can't see a good solution for is arrays. A newly constrcuted
>> array is full of null pointers, and you can initialize all of the members
>> perhaps 10% of the time. I think you have to accept that
>
> Just insist on using collections instead...
And how does one implement the collections without using arrays? :-)
Finalizers, which can see partially constructed objects, too.
They can. Normally through calling virtual methods. But this can be
casted as well.
> My point about finals was probably unclear. I meant that the compiler
> already knows how to check than finals get set from every constructor; they
> can equally well check that any non-nullable field gets set from every
> constrcutor.
You can all to easily see final variables before they are initialised.
> And how does one implement the collections without using arrays? :-)
Magic black box. I believe Eiffel does something similar.
> > Off and on, I've been playing with the idea that there could be two
> > kinds of references in Java: those that can contain "null" as a value
> > and those that can't. Assigning null to a non-nullable reference
> > would be illegal. Assigning a nullable reference to a non-nullable one
> > would require a cast and might result in an NPE then and there, so that
> > the NPE points to the logical error, rather than occurring later when
> > some perfectly innocent code trips over the null pointer.
>
> Nice does that.
More info here:
http://nice.sourceforge.net/manual.html#optionTypes
and here:
http://nice.sourceforge.net/cgi-bin/twiki/view/Doc/OptionTypes
(down at the bottom of the page).
It's not clear whether Nice has any special means to allow an instance field
with a non-nullable type to be initialised only in the ctor. I suspect that
you have to initialise it statically (as it were), and if necessary change the
default in the ctor.
AFAIKT, the Nice collections implementation is layered over the Java stuff, so
it's not possible to see how they'd solve the "the underlying array may contain
nulls but I know it's not null at this index" problem. I presume that it would
require logically unnecessary runtime checks in order to satisfy the compiler.
-- chris
Kan? :-)
True, but at least you can't leave them uninitialized.
Note that fields cause two sorts of problems.
1. It's possible to see them before they're initialized, thus you see a
null you're not expecting.
2. It's difficult if not impossible to prevent:
NN1 = this.NN2; // both declared non-nullable, but NN2 has not yet been
set.
The first can cause NPEs at that line. The second can result in NPEs
anywhere, which is much worse. In fact, it's exactly like Java today.
[me:]
> > AFAIKT, the Nice collections implementation is layered over the Java
> > stuff,
>
> Kan? :-)
Aargh!
Would you believe me if I claimed: As Far As I Know Today ? No ? Oh, well....
-- chris
Remove all asymptotic runtime guarantees and implement everything using
linked lists and binary trees?
- Oliver