![]() |
|
|
|
#21 |
|
(attribution restored)
Lew wrote: >> But you cannot expect the compiler to catch all your mistakes. So >> this was one that it couldn't catch because in their infinite wisdom >> the Powers That Be decreed that 'Map#get()' not be type >> parameterized. Mike Schilling wrote: > Which we still don't have a good explanation for. The closest to a What, "infinite wisdom" isn't a good enough explanation? > real use case for get(Object) rather than get(K) we've seen is > Patricia's, and that could be made to work with get(K) simply enough > by letting K be List instead of ArrayList. One of the beauties of the Java community is that the practitioners don't blindly accept all the language's features with religious fervor, but question and challenge pretty nearly all its decisions. This bodes well for the health of the platform. "No one pretends that Java is perfect or all-wise. Indeed, it has been said that Java is the worst programming language except all those others that have been tried from time to time." (With apologies to Sir Winston Churchill) -- Lew Lew |
|
|
|
|
#22 |
|
Posts: n/a
|
In article <hcb95q$mvt$>, Lew <>
wrote: > Kevin McMurtrie wrote: > > Generics is extremely helpful for common source code mistakes but it is > > by no means a powerful tool. There have been many, many long threads > > about it here. > > There may have been long threads about it, but generics most assuredly is a > powerful tool. Perhaps you just haven't learned to use it correctly yet. I think my expectations of a 'powerful tool' are greater than yours. -- I won't see Goolge Groups replies because I must filter them as spam Kevin McMurtrie |
|
|
|
#23 |
|
Posts: n/a
|
Lew wrote:
> (attribution restored) > Lew wrote: >>> But you cannot expect the compiler to catch all your mistakes. So >>> this was one that it couldn't catch because in their infinite >>> wisdom >>> the Powers That Be decreed that 'Map#get()' not be type >>> parameterized. > > Mike Schilling wrote: >> Which we still don't have a good explanation for. The closest to a > > What, "infinite wisdom" isn't a good enough explanation? Call me picky. Mike Schilling |
|
|
|
#24 |
|
Posts: n/a
|
Kevin McMurtrie wrote:
> In article <hcb95q$mvt$>, Lew <> > wrote: > >> Kevin McMurtrie wrote: >>> Generics is extremely helpful for common source code mistakes but it is >>> by no means a powerful tool. There have been many, many long threads >>> about it here. >> There may have been long threads about it, but generics most assuredly is a >> powerful tool. Perhaps you just haven't learned to use it correctly yet. > > I think my expectations of a 'powerful tool' are greater than yours. I think it's question of how powerful, and that there are objective rationales for calling generics powerful. Generics permit one to lock down the type relationships in code and push possible runtime exceptions into compiler messages. The industry rule of thumb is that compile time fixes are ten times cheaper than run time fixes. Ten to one is powerful. Generics force one to thoroughly analyze the type relationships. They directly express that analysis. Type analysis is very powerful and the ability to express it commensurately so. Documentation internal to code is powerful. It speeds understanding for maintenance programmers and prevents their errors. Generics increase the ability to refactor code safely. If a type parameter for interface 'Blah' is '<T extends Collection <Foo> & Serializable>' one can reify that as 'ArrayList' initially and refactor to 'HashSet' without pain. One will not be able to accidentally substitute a non-serializable collection. One will be able to extract 'Foo' elements safely. Client code can ignore the details secure in those promises. Encapsulation is powerful: public interface Blah <T extends Collection <Foo> & Serializable> { T getItems(); } Client: Blah <?> blah = BlahImpl.make(); Collection <Foo> foos = blah.getItems(); Information hiding, type safety, easier and less risky refactoring, simpler client code - taken together they show that generics are at least somewhat powerful. -- Lew Lew |
|
|
|
#25 |
|
Posts: n/a
|
Wojtek wrote:
> Or rather, why does the spec not say get(K key) instead of get(Object o) I'm not really sure why this is. Possibly the designers felt the same way many in the news group do -- get(Object) is correct. This doesn't really answer your question, but if you need (or feel you will benefit from) a map with a parameterized get(K), then it's not really hard to add one: public interface MapWithGenericGet<K, V> extends Map<K, V> { V getGeneric( K key ); } class HashMapWithGenericGet<K, V> extends HashMap<K, V> implements MapWithGenericGet<K, V> { @Override public V getGeneric( K key ) { return get( key ); } } I don't know why the API designers didn't add such a thing. Maybe they figured no one would really use it. But it's safe and easy enough to do yourself. You just have to remember to use getGeneric() instead of plain old get(). markspace |
|
|
|
#26 |
|
Posts: n/a
|
Wojtek wrote:
> If I have the following: > > HashMap<MyKey,MyValue> map = new HashMap<MyKey,MyValue>(); > [...] > Or rather, why does the spec not say get(K key) instead of get(Object o) Map<Politician,Party> congress = new HashMap<Politician,Party>(); congress.put(new Politician("Barney Frank", Party.DEMOCRATIC); congress.put(new Politician("Dan Lungren", Party.REPUBLICAN); ... // returns Party.DEMOCRATIC Party p = congress.get(new Politician("Brad Ellsworth")); // returns null Party q = congress.get(new Politician("Dan Rostenkowski")); Pretty straightforward: We've got a Map that gives us the party affiliation of any member of Congress, or that returns null if we ask about someone who's not in Congress. Clear? Okay, then // returns null Party r = congress.get(new HonestPerson("Mother Teresa")); Again we get a null, because Mother Teresa is not in Congress. We could have known that without asking, because no Politician is an HonestPerson and hence no HonestPerson can be in our map, but if we ask anyhow the map is perfectly capable of delivering the right answer: Mother Teresa is not a member of Congress. There is nothing wrong with asking a self-answering question, like "What color was George Washington's white horse?" When calling get() on a Map, the program must already be ready to deal with the possibility that the Map does not contain the offered key, so offering an "impossible" key merely exercises that code path. If a program has reason to believe that every key it asks about is in fact in the Map, "deal with" may be merely "ignore until you get a NullPointerException," but that's not the Map's fault: You ask for something that's not there (that, perhaps, could not possibly be there), and you're told it's absent, and that's the right answer. Elsethread, I gather that you went through an unpleasant time when you changed your `congress' from Map<Person,Party> to Map<Politician,Party> (or something like that). You also went around and changed a lot of get() calls to offer Politician references, but you missed a few that were still trying to look up Persons, with the result that you started getting nulls at unexpected times. Well, yeah, that's always a problem when you change something in one place and overlook some of the other places that need corresponding changes. If you do this again, I'd suggest changing the Map's name at the same time, from `congress' to `bigmess' or something, and let the compiler draw your attention to *every* place the Map is used so you can see if a change is needed. After you've fixed them all, you can rename `bigmess' to `congress' again -- if you like. -- Eric Sosman lid Eric Sosman |
|
|
|
#27 |
|
Posts: n/a
|
Eric Sosman wrote:
> [...] > Map<Politician,Party> congress = > new HashMap<Politician,Party>(); > congress.put(new Politician("Barney Frank", Party.DEMOCRATIC); > congress.put(new Politician("Dan Lungren", Party.REPUBLICAN); Drat! I'm missing some right parentheses here; should be congress.put(new Politician("Barney Frank"), Party.DEMOCRATIC); congress.put(new Politician("Dan Lungren"), Party.REPUBLICAN); -- Eric Sosman lid Eric Sosman |
|
|
|
#28 |
|
Posts: n/a
|
Peter Duniho wrote:
> I know what I suspect: since HashMap (and Map) pre-date generics in > Java, the types already have an overload that takes Object as an > argument. Due to the decision to reuse the existing implementations > for the non-reified generics feature in Java, there wasn't any > feasible way to eliminate the possibility of passing an Object (thus the > compile-time assurance I mentioned earlier isn't really a benefit > available in Java), and absent that there just wasn't a strong > argument _against_ allowing Object as an argument. Not true. The same feature of generics that controls the arguments to put() could have controlled the argument to get(). A deliberate decision was made to have get(Object) instead of get(K) [1], and reification has nothing to do with it. 1. Likewise Set.contains(Object) and Set.containsAll(Collection<?>), but Set.addAll(Collection<E>). Very consistently, you can add only something of the proper type, but you can look for things of any type at all. Mike Schilling |
|
|
|
#29 |
|
Posts: n/a
|
Peter Duniho wrote:
> Mike Schilling wrote: >> Peter Duniho wrote: >>> I know what I suspect: since HashMap (and Map) pre-date generics in >>> Java, the types already have an overload that takes Object as an >>> argument. Due to the decision to reuse the existing implementations >>> for the non-reified generics feature in Java, there wasn't any >>> feasible way to eliminate the possibility of passing an Object >>> (thus the compile-time assurance I mentioned earlier isn't really a >>> benefit available in Java), and absent that there just wasn't a >>> strong argument _against_ allowing Object as an argument. >> >> Not true. The same feature of generics that controls the arguments >> to put() could have controlled the argument to get(). A deliberate >> decision was made to have get(Object) instead of get(K) [1], and >> reification has nothing to do with it. > > Perhaps you're simply misunderstanding what I'm saying. It's not true > that what I wrote is not true. > > In .NET, for example, there is _no way_ to call the Add() method of a > generic collection without providing an element of the correct type. > Not even using reflection can it work. Right. Reification gives you that. > > In Java, you have type erasure. As long as you're dealing with > generically-declared accesses to the data structure, you have the > protection of the specific declared type. But this is easily > circumvented. There's no way at compile time for Java to _guarantee_ > that you haven't misused the type, never mind at runtime. > > To the extent that this is a risk, we just live with it for methods > that modify the collection. Java protects us as best it can, and you > have to go at least a little out of your way to circumvent the type > protection. > But for harmless scenarios where there's not necessarily even a data > corruption/runtime error consequence, and some might see some benefit, > they've actually exposed the typed erasing as part of the primary > generic API. My suggestion is that the reasoning might be that since > some people might actually _want_ to do this, and there's no way to > 100% protect against it, they went ahead and opted for slightly more > utility. OK, I see what you're saying now, and I can't categorically call it untrue. Clearly the designers thought that someone might want to do that, since they didn't make the slight effort that would have prevented it. But I don't see any evidence whether they would have made that same decision with a newly created, reified collections framework. Mike Schilling |
|
|
|
#30 |
|
Posts: n/a
|
Peter Duniho wrote:
> [... in re get(Object) on a Map<K,V> ...] > I see a particular benefit in constraining the > argument; in particular, it allows one at compile time to avoid writing > code that you know will always fail. So there must be some other > benefit that offsets that one, justifying the current design. Maybe the debate is about this word "fail." In one sense, if you look for something in a Collection that doesn't contain it, the search "fails." In another sense, it "succeeds" in determining the absence of the sought object. It is not a given that finding something in a Map is the "normal" case and finding that it's not there is a "failure." An result of "not there" can even be the desired outcome: Imagine a demolition foreman checking for people in the building before firing the explosives to bring the thing down. A negative answer is not ipso facto a "failure." Yes, it is a Good Thing to prevent failures -- but that's not the same thing as preventing negative answers. -- Eric Sosman lid Eric Sosman |
|