HashMap get/put

L

Lew

(attribution restored)

Mike said:
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)
 
K

Kevin McMurtrie

[QUOTE="Lew said:
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.[/QUOTE]

I think my expectations of a 'powerful tool' are greater than yours.
 
L

Lew

Kevin said:
[QUOTE="Lew said:
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.[/QUOTE]

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.
 
M

markspace

Wojtek said:
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().
 
E

Eric Sosman

Wojtek said:
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.
 
E

Eric Sosman

Eric said:
[...]
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);
 
M

Mike Schilling

Peter said:
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.
 
M

Mike Schilling

Peter said:
Mike said:
Peter said:
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.
 
E

Eric Sosman

Peter said:
[... 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.
 
M

Mike Schilling

Eric said:
Peter said:
[... 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.

Then why Class.isAssignableFrom(Class<?> cls) instead of
Class.isAssignableFrom(Object cls) ? It could simply return false if cls
isn't a Class.
 
A

Arved Sandstrom

Lew said:
That would be true except that that particular example doesn't meet the
requirement of being self-answering, in that the answer is "grey".

It's a trick question. In the horse world, white horses are not known
as "white" but as "grey", just like reddish-brown ones are called
"bay". It's an equestrian thing.

Another trick question is, "Which weighs more, a pound of gold or a
pound of feathers?" It turns out that they do not weigh the same.
I stand to be corrected, but I don't think the troy pound is used any
more, just troy ounces. So a pound of gold is avoirdupois weight.

AHS
 
M

Mike Schilling

Peter said:
But your example simply reinforces my point. In a framework with
reified generics, looking for a dictionary entry using an object of
the wrong type wouldn't make sense at all.

Why not? Keys of different types could still be equal.
 
L

Lew

Arved said:
I stand to be corrected, but I don't think the troy pound is used any
more, just troy ounces. So a pound of gold is avoirdupois weight.

That may be true in recent times, but the riddle is older than that and was
designed as a trick question.

Many such jokes have lost their humor because of cultural and linguistic
changes. "That's no lady, that's my wife!" is an example - the term "lady"
used to carry connotations of upper-class elitism.

Even today, about three-quarters or more of the google hits on the gold vs.
feathers question assert that the pound of feathers weighs more.
 
M

Mike Schilling

Peter said:
By definition, they would not be equal for the purpose of being a
matching key for a value in the collection. If you want keys of
different types to all be valid keys, you would use a common base
type
instead (Object, if necessary).

You say this as if it were synonomous with reification, but you
haven't shown that.
 
M

Mike Schilling

Lew said:
Even today, about three-quarters or more of the google hits on the
gold vs. feathers question assert that the pound of feathers weighs
more.

It might be true anyway. Though if Wikipedia also thinks the feathers
weigh more, it's pretty much a lost cause.
 
L

Lew

Mike said:
It might be true anyway. Though if Wikipedia also thinks the feathers
weigh more, it's pretty much a lost cause.

I assume you mean, "if Wikipedia also thinks that feathers use avoirdupois
pounds and gold uses troy pounds, thus a pound (avoirdupois) of feathers
weighs more than a pound (troy) of gold, it's pretty much a lost cause."

Wikipedia, that bastion of encyclopedic and infallible truth that one should
never, ever doubt, says that precious metals are weighed in troy ounces but
not troy pounds.
<http://en.wikipedia.org/wiki/Troy_weight>
<http://www.troy-ounce.com/> agrees, though it cites the Wikipedia article as
one of its sources, so perhaps that doesn't surprise.

This is not true.

<http://www.sizes.com/units/troy_weight.htm>
tells us that "n the United States, troy weight remains legal," and directs
us to page 20 of the 1982 "Uniform Regulation for the Method of Sale of
Commodities, model legislation proposed for adoption by individual states by
the National Conference on Weights and Measures."
> 2.17.2. Quantity. --
> The unit of measure and the method of sale of precious metals,
> if the price is based in part or wholly on a weight determination,
> shall be either troy weight or SI units.

<http://www.goldcalculator.com/index_files/page0033.htm#Troy Pound (0.37kg):>
calls the troy pound a "mass unit is used to measure precious metals."

<http://scienceworld.wolfram.com/physics/TroyPound.html>
asserts that troy pounds are used to measure precious metals.

<http://www.govmint.com/item/Classic-Half-Troy-Pound-Bag-of-US-Silver/1803581/2>
offers silver weighed in terms of troy pounds, proving definitively that
someone, at least, still uses that unit for precious metal.

Same for
<http://www.shopwiki.com/Bags+of+Buffalo+Nickels+New+Half+Troy+Pound+Bag+of+Buffalo+Nickels+III>
<http://www.dondienterprises.com/id12.html>
<http://www.milliondollarbill.com/goldfinger01.html>
and many other current commercial sites.

The fact that precious metals (or simulations thereof) are actually sold by
troy pounds proves that the unit is still in use. Ergo, a pound (troy) of
gold is lighter than a pound (avoirdupois) of feathers.

The question remains tricky.
 
A

Arved Sandstrom

Lew wrote:
[ SNIP ]
The fact that precious metals (or simulations thereof) are actually sold
by troy pounds proves that the unit is still in use. Ergo, a pound
(troy) of gold is lighter than a pound (avoirdupois) of feathers.

The question remains tricky.

You'd have to decide what country you ask the riddle in. In the US it
still applies, as you pointed out. In the UK, Canada, Australia, and
divers other jurisdictions it no longer does. For example, the Canada
Weights and Measures Act, under the Canadian Units section, allows for
the troy ounce to measure precious metals, but not the troy pound.
Similarly, the UK Weights Measures Act disallows use of the troy pound.
And so on and so forth.

I agree that it's an old riddle, but the trick answer depends on the
legal system of weights and measures being used at the specific time and
place of asking. It'll have no meaning at all sometime in the future
when Imperial measures completely die as legal units of trade.

AHS
 
J

Joshua Cranmer

I think the equals design was a consequence of some deeply embedded
decisions, especially the idea that all instance methods are virtual (in
C++ terminology - the distinction I am making does not exist in Java).

To be pedantic, private methods in Java are not virtual.
 
M

Mike Schilling

Lew said:
I assume you mean, "if Wikipedia also thinks that feathers use
avoirdupois pounds and gold uses troy pounds, thus a pound
(avoirdupois) of feathers weighs more than a pound (troy) of gold,
it's pretty much a lost cause."

Nothing so complicated; I just meant that Wikipedia's usually wrong.
 

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,744
Messages
2,569,483
Members
44,902
Latest member
Elena68X5

Latest Threads

Top