Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / General / January 2006

Tip: Looking for answers? Try searching our database.

generic oversight?

Thread view: 
VisionSet - 30 Dec 2005 19:47 GMT
When they retro fit generics to Collection classes why didn't they change
methods like this

containsKey(Object key)

to

containsKey(K key)

I was in secure type safe heaven for a bit...

--
Mike W
Thomas Hawtin - 30 Dec 2005 20:37 GMT
> When they retro fit generics to Collection classes why didn't they change
> methods like this
[quoted text clipped - 6 lines]
>
> I was in secure type safe heaven for a bit...

On the face of it, it doesn't look type unsafe, does it? I mean if you
give me a HashMap with a String key and I look for an Integer in it, I
just wont find any (unless it's a null reference, possibly).

If I take you Map<String,Void> and assign it to Map<?,Void>, that should
work. I've forgotten the type of the key, but really is there any
problem with me looking up a key in it? And in order to do that, your
contains key needs to be more relaxed. Something like:

    boolean containsKey(? super K key); // NOT LEGAL

That's not legal. Although if it was, appropriate semantics could make
it illegal to check whether a Map<String,Void> contains an Integer key.
The nearest we can get to the above is:

    boolean containsKey(Object key);

TreeMap introduces complications because the Comparator/Comparable may
throw a ClassCastException. If we wanted to check the comparator, then
the Map interface would need to develop a third generic parameter, that
would almost always be irrelevant. Alternatively, I guess TreeMaps could
do a preliminary check, but unfortunately the never did so can't really
if backward compatibility is to be maintained (and they don't have the
K.class).

Tom Hawtin
Signature

Unemployed English Java programmer
http://jroller.com/page/tackline/

ricky.clarkson@gmail.com - 31 Dec 2005 13:01 GMT
Mike,

For this (and other) reasons I implemented my own collection wrappers,
which wrap Collection, List, etc., but have more sane API, including
contains(T).  This isn't currently public, because I'm lazy, but it
could be.

You can either suggest that it should be public, which might kickstart
me to making it so, or implement your own.  However, I doubt Sun will,
because they're afraid to stop old code from compiling.

Cheers.
VisionSet - 31 Dec 2005 13:23 GMT
> Mike,
>
[quoted text clipped - 6 lines]
> me to making it so, or implement your own.  However, I doubt Sun will,
> because they're afraid to stop old code from compiling.

Thanks Ricky, it's enough to know I'm not going mad and missed something.
I'm aware now to not assume a class I know is Generified is not necessarily
completely so.
Would be a nice feature for serious use though.

--
Mike W
Thomas Hawtin - 31 Dec 2005 13:50 GMT
> For this (and other) reasons I implemented my own collection wrappers,
> which wrap Collection, List, etc., but have more sane API, including
> contains(T).  This isn't currently public, because I'm lazy, but it
> could be.

The collections are fundamentally part of the Java language. If I see
code using collections, then I expect it to be all standard stuff. No
need to look anything up. There is a high price to pay for going
non-standard.

Tom Hawtin
Signature

Unemployed English Java programmer
http://jroller.com/page/tackline/

ricky.clarkson@gmail.com - 02 Jan 2006 00:13 GMT
I disagree.  There is a high price for bugs.  Writing/using a separate
library is easy.

If having ipsim.util.List and java.util.List confuses you, call it
something else, as ContractualJ ( www.contractualj.com ) does (Sequence
and other names).

I found keeping the names the same made it easy to adapt existing code
- most of the time I just changed the imports.  It would be trivial to
refactor now I suppose, but I don't see the point.

If you really believe that using something that is non-standard is
harmful, then it will be difficult to make progress.

Apologies to all if this is a repeated post, I got mildly confused.
Thomas Hawtin - 02 Jan 2006 11:45 GMT
> I disagree.  There is a high price for bugs.  Writing/using a separate
> library is easy.

How many bugs have you had from containsKey taking Object? How many have
other people had?

> If having ipsim.util.List and java.util.List confuses you, call it
> something else, as ContractualJ ( www.contractualj.com ) does (Sequence
> and other names).

List.contains is a poorer example than Map.containsKey. I don't know of
any implementation of List.contains that throws ClassCastException. A
non-List Collection from TreeMap/TreeSet may.

> I found keeping the names the same made it easy to adapt existing code
> - most of the time I just changed the imports.  It would be trivial to
> refactor now I suppose, but I don't see the point.

Deliberately clashing names with common, standard types is something I
am heavily against. See Josh Bloch's Effective Java. At least do the
Swing thing and add an initial initial.

> If you really believe that using something that is non-standard is
> harmful, then it will be difficult to make progress.

Making arbitrary changes to mature, tested and very well established
libraries, designed by some quite clever people, is not progress.
Progress is 10% innovation and 90% standardisation (I just made that up,
if you can't tell). Standing on the shoulders of giants, that sort of thing.

If you have a contempt for standardisation and want to avoid NPEs and
CCEs, then write a new language rather than corrupt an existing one.

To stay in Java and avoid these CCEs, write wrappers that check types.
The wrappers can implement the standard interfaces, so there are only
small changes necessary for conventional code. The problem is so obscure
that Collections.checkedMap and friends don't bother with it.

Tom Hawtin
Signature

Unemployed English Java programmer
http://jroller.com/page/tackline/

ricky.clarkson@gmail.com - 02 Jan 2006 19:17 GMT
> How many bugs have you had from containsKey taking Object? How many have
> other people had?

I think I've said this elsewhere recently, so sorry if you're reading
this twice:

I had various things like List<ComponentHandler> and decided to change
them to List<NetworkComponent>.  I could do most of this by looking at
the compile errors, fairly easy to go through my codebase and fix.
Then I started testing, and kept finding cases where I was doing
componentList.indexOf(handler), which will always return false.

So I changed to using ipsim.util.List and the compiler picked up the
errors.

I can't accurately vouch for other people, but surely if there was no
problem then the OP wouldn't have posted.

I don't know what you mean with ClassCastException.  I don't want
ClassCastException, I want compile errors.

> Deliberately clashing names with common, standard types is something I
> am heavily against. See Josh Bloch's Effective Java. At least do the
> Swing thing and add an initial initial.

I will see that book sometime.  Meanwhile, I don't see it as a problem
because I am *replacing* java.util.List in my code.  I don't want to
even consider using both together.  Plus, we have packages, so there
already are separate namespaces.

> Making arbitrary changes to mature, tested and very well established
> libraries, designed by some quite clever people, is not progress.

I still use the same implementations, I respect the efforts made to
make ArrayList grow smoothly, etc., but I just want a slightly
different interface, so I wrapped it.

I am allowed to disagree with these 'clever people'.

> If you have a contempt for standardisation and want to avoid NPEs and
> CCEs, then write a new language rather than corrupt an existing one.

I'm not corrupting anything.  I am making new APIs.  I believe Java is
flexible enough to support experimentation into APIs without having to
involve a new programming language at every turn.  On the other hand it
is also too flexible without code checking tools for many people's
requirements.

I don't dislike standardisation, but I don't see why it should be done
arbitrarily.  There should be reasons for things that are in standards.
I haven't seen a reason from anyone 'quite clever' yet that explains
why contains is not generic.
Chris Smith - 03 Jan 2006 18:35 GMT
> I don't dislike standardisation, but I don't see why it should be done
> arbitrarily.  There should be reasons for things that are in standards.
>  I haven't seen a reason from anyone 'quite clever' yet that explains
> why contains is not generic.

Thomas gave you that answer on Friday, at 1:45 PM in my local time.  You
responded.  If you weren't observant enough to see it, that's not anyone
else's fault.

Here's the reason again, in slightly different terms.  If List<T> had a
contains(T) method rather than a contains(Object) method, then the
following code would become illegal:

   List<?> someList = something.getList();
   Object key = something.getKey();

   if (someList.contains(key)) System.out.println("Hello!");

This should be legal code.  I should be able to check if the list
contains the object.  I don't need to know the element type for someList
(the type parameter) in order to test for membership.  Forcing me to do
so may force me to introduce unnecessary dependencies of more stable
code on less stable code, which causes problems with maintenance.

There's a broader point here, though, which Thomas also made.  A group
of really smart people led the development of the Collections API.  They
didn't make dumb mistakes.  There may have been better design choices,
but they weren't stupid and they weren't careless.  You showed up on a
public discussion forum, claimed that their design choices aren't even
sane.  You suggested that other people should abandon use of the
Collections API, and instead wrap it with their own classes that make
ill-considered changes to the API, which you decided upon on your own,
without any consultation with other people, without forming a group of
experts like the ones involved in designing the Collections API.

Then you tricked people, who -- like you -- don't understand the
problems involved, into doing something that's not smart.

In short, you could stand to learn some humility.  Thomas's points about
standardization all come down to that (plus some very important
practical issues that I might explain in a later post... but that ought
to be enough).

Signature

www.designacourse.com
The Easiest Way To Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation

Chris Smith - 03 Jan 2006 19:06 GMT
> > Deliberately clashing names with common, standard types is something I
> > am heavily against. See Josh Bloch's Effective Java. At least do the
> > Swing thing and add an initial initial.
>
> I will see that book sometime.

A good time to read Josh's very excellent book might be BEFORE you start
giving advice on newsgroups that assumes that Joshua Bloch is an idiot.

> Meanwhile, I don't see it as a problem
> because I am *replacing* java.util.List in my code.  I don't want to
> even consider using both together.

Hope you don't have to interact with anyone else's code, then.  They are
likely to give you standard collections.  You're going to spend a whole
heap of time communicating between the two.

In general, I'd say that anything that prevents you from (or makes
difficult) using existing solutions to difficult problems is a bad
thing.  This is one of the important reasons that standard collections
came about in the first place.  People communicate collections between
different pieces of code.

> I am allowed to disagree with these 'clever people'.

Not until you understand both the reasons for their decisions, and the
consequences of breaking them.  Even an extremely poor standard object
that can be used for communication between several modules of code is
often better than a perfect non-standard implementation.  Since you are
providing far from perfect alternative, you have quite a bar to clear
before it becomes worth making the change.

Again, I have no problem with you doing something dumb.  I have a
problem with you convincing others to do something dumb.

Signature

www.designacourse.com
The Easiest Way To Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation

ricky.clarkson@gmail.com - 04 Jan 2006 04:56 GMT
Chris,

Quite a love affair this is.

List<?> someList = something.getList();
If you make that into List<? extends Object> then you could use
contains(new Object()) on it, I think, with my amazingly dumb API.  I
haven't tested this.  I don't use ? for anything myself.

Regarding sanity, someone famous once said something along the lines of
"wars start because everyone believes everyone else is a little bit
insane".  Point taken though, I should be a little more careful with my
choice of words.  It wasn't meant as an insult to any person or
organisation.

As a 'full' user of generics, as far as I know, I don't need the ?
notation, so the use case of wanting to look for an arbitrary object in
a List<?> doesn't arise for me.  I don't know when you might want a
List<?>, so given that exception, maybe I made a mistake.

A possibility without doing a lot to existing code would be something
like:

final class CollectionUtility
{
  public static <T> boolean contains(T object,List<T> list)
  {
     return list.contains(object);
  }
}

I also implemented read-only interfaces, e.g., ListView, MapView, and
used it partially to eliminate bugs and partially as an experiment into
how I would go about implementing collections from scratch myself.
That, I think, gave me a better understanding of generics, and a better
understanding of the existing implementations.  I think both of these
goals are fine.

My new interfaces might not be useful with the ? notation, but I don't
need them to be.  That's ok.  I haven't published them, only the idea
of them, and even if I did, it would not be a bad thing.  The original
poster, for example, might try out my interfaces, or just read about
them, with the comment that they won't work well for
List<?>.contains(Object), and decide against using them.  That's fine,
it's good, the OP would have been educated.

I firmly believe it's better to try new ideas than to unknowingly stick
with old ideas.

> A good time to read Josh's very excellent book might be BEFORE you start
> giving advice on newsgroups that assumes that Joshua Bloch is an idiot.

I did not say ANYTHING against Joshua Bloch.  Kindly try not to put
words in my mouth.  I knew he had something to do with the development
of Java's enums; I didn't have a clue he was involved in generics too.

> I have a
> problem with you convincing others to do something dumb.

That's just one of the advantages of a public forum, isn't it.  I can
suggest something, you can shoot it down, hopefully with good arguments
that make the OP able to make an informed decision.  I could have
emailed him privately with a jar file full of these interfaces, but I
didn't.  You'll kindly note that I didn't force my ideas on the OP.  I
told him what I did, and what he could do if he wanted to follow the
same route.  Again, my language could have been better.  I'm fairly new
to newsgroups.

Cheers.
Chris Smith - 04 Jan 2006 06:29 GMT
> List<?> someList = something.getList();
> If you make that into List<? extends Object> then you could use
> contains(new Object()) on it, I think, with my amazingly dumb API.  I
> haven't tested this.  I don't use ? for anything myself.

No, that's not true.  You'd have to use List<? super Object>, which is
of course equivalent to List<Object>.

If you don't use wildcards for generics, how do you avoid spending
massive amounts of time copying generic data structures from one to
another?  Do you never store objects that belong to interesting
inheritance trees in generic collections?

> As a 'full' user of generics, as far as I know, I don't need the ?
> notation, so the use case of wanting to look for an arbitrary object in
> a List<?> doesn't arise for me.  I don't know when you might want a
> List<?>, so given that exception, maybe I made a mistake.

You might want a wildcard List if implementing any generic utility
method designed to work with Collections.  Generally you do want some
bounds.  For example:

   public <T> List<T> concat(List<? extends T> a, List<? extends T> b)
   {
       List<T> result = new LinkedList<T>();

       result.addAll(a);
       result.addAll(b);

       return result;
   }

...

   List<Dog> d = new LinkedList<Dog>();
   List<Cat> c = new LinkedList<Cat>();

   List<Animal> a = concat(d, c);

It's more complex to create a realistic situation in which case you
might want a wildcard list with no bounds at all.  It generally involves
interoperating with external code at some significant level of detail.  
But it does happen.

> final class CollectionUtility
> {
[quoted text clipped - 3 lines]
>    }
> }

The method you provided can only be used with a List<? super X> (or a
List<X>, of course) for some X that is a supertype of the type of the
first parameter.  In other words, it doesn't accomplish anything more
than your original proposal for List.contains(T).

> I also implemented read-only interfaces, e.g., ListView, MapView, and
> used it partially to eliminate bugs and partially as an experiment into
> how I would go about implementing collections from scratch myself.

There are, of course, Collections.unmodifiableList,
Collections.unmodifiableMap, and Collections.unmodifiableSet.  If you
don't like the decision to use optional operations, see the file called
designfaq.html in the docs/guide/collections directory of any Java 1.5
SDK installation.  There are very good reasons given there for making
that decision... some empirical and some logical in nature.

That said, I'm surprised that you implemented these views and still
haven't used wildcards.  That seems rather difficult to believe.

> My new interfaces might not be useful with the ? notation, but I don't
> need them to be.  That's ok.

The need for wildcards in generics is not limited to working with other
code that uses wildcards.  If you wrote code that doesn't use wildcards,
it won't work well with other perfectly good code that does NOT use
wildcards.  Wildcards turn out to be logically necessary in the Java
generics type system.

Signature

www.designacourse.com
The Easiest Way To Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation

Chris Uppal - 04 Jan 2006 11:20 GMT
> When they retro fit generics to Collection classes why didn't they change
> methods like this
[quoted text clipped - 4 lines]
>
> containsKey(K key)

I'm not sure if anyone has actually answered this...

First off, they couldn't /replace/ containsKey(Object) with containsKey(K)
since that would break backward compatibility with code that expected the
former method to exist.  Secondly they couldn't just /add/ containsKey(K) since
that would not necessarily be distinct from containsKey(Object) -- K might be
Object.  Lastly they couldn't use hacky magic like that which allows, say,
String to implement Comparable<String> with a method

   int compareTo(String)

which magically implements the Comparable (i.e. post-erasure) interface's
requirement for a method:

   int compareTo(Object)

because that's done by synthesising a method:

   int compareTo(Object o) { return compareTo((String)o); }

Using an equivalent hack in this case would either result in a
containsKey(Object) method which threw class-cast exceptions rather than
answering false (thus breaking the previously established contract), or would
require the compiler to "know" somehow that the synthetic bridge method should
read:

   boolean
   containsKey(Object o)
   {
       return (o instanceOf K)
           ? containsKey((K)o)
           : false;
   }

which is impossible for at least two reasons...

   -- chris


Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.