Go Back   Velocity Reviews > Newsgroups > Java
User Name
Password
Register FAQ Members List Calendar Search Today's Posts Mark Forums Read

Reply

Java - HashMap get/put

 
Thread Tools Search this Thread
Old 10-31-2009, 09:18 PM   #41
Default Re: HashMap get/put


Peter Duniho wrote:
> Thomas Pornin wrote:
>> The Java compiler emits an invokevirtual opcode even for a final
>> method, because the class which contains the final method and
>> against
>> which the call site is compiled may be substituted later on with
>> another version which lacks the 'final'.

>
> I'm afraid I don't understand how that can be. If you have a type
> known at compile time to have a final method, how can that type be
> substituted later on with a version in which that method is not
> final? Do you have to do something with a special class loader? Or
> is there actually language (as opposed to framework) support for
> doing that?


The called class might haver changed at run-time; such a change
doesn't require that the caller be recompiled.




Mike Schilling
  Reply With Quote
Old 10-31-2009, 09:35 PM   #42
Mike Schilling
 
Posts: n/a
Default Re: HashMap get/put
Peter Duniho wrote:
> Mike Schilling wrote:
>> Peter Duniho wrote:
>>> Thomas Pornin wrote:
>>>> The Java compiler emits an invokevirtual opcode even for a final
>>>> method, because the class which contains the final method and
>>>> against
>>>> which the call site is compiled may be substituted later on with
>>>> another version which lacks the 'final'.
>>> I'm afraid I don't understand how that can be. If you have a type
>>> known at compile time to have a final method, how can that type be
>>> substituted later on with a version in which that method is not
>>> final? Do you have to do something with a special class loader?
>>> Or
>>> is there actually language (as opposed to framework) support for
>>> doing that?

>>
>> The called class might haver changed at run-time; such a change
>> doesn't require that the caller be recompiled.

>
> That seems like a serious versioning problem. What happens if you
> have a class where the method is changed from non-final to final?
> Does code compiled with that class previous still get to override
> the
> now-final method?


I think it'll fail to load, but I wouldn't swear to it.




Mike Schilling
  Reply With Quote
Old 11-01-2009, 04:06 PM   #43
Eric Sosman
 
Posts: n/a
Default Re: HashMap get/put
Peter Duniho wrote:
> Mike Schilling wrote:
>> [...]
>> The called class might haver changed at run-time; such a change
>> doesn't require that the caller be recompiled.

>
> That seems like a serious versioning problem.


<Shrug.> If you want the freedom of run-time binding, you've
got to accept the consequences.

> What happens if you have
> a class where the method is changed from non-final to final? Does code
> compiled with that class previous still get to override the now-final
> method?


No, of course not. Similarly, if class A uses a public method
of class B, and then a new class B changes the method to private,
the already-compiled A can no longer use B's method.

> I suppose that's one argument in favor of making all methods use virtual
> dispatch, final or not. Then the method call always works the same
> regardless. But it does seem to mean that if the contract for the class
> changes, older code may wind up violating the new contract.


Yes, although it's not at all clear which party "violates" a
contract that's amended unilaterally.

The compiler will make sure that everything is kosher at the
time of compilation, but it cannot predict the future. The JVM,
looking at the actual .class files presented to it, is the final
arbiter of whether they'll play together or not.

--
Eric Sosman
lid


Eric Sosman
  Reply With Quote
Old 11-02-2009, 06:06 AM   #44
Mike Schilling
 
Posts: n/a
Default Re: HashMap get/put
Peter Duniho wrote:

>
> I think I see the disconnect here. I'm talking about the eventual
> native code being executed. When possible (i.e. in C# for methods
> that aren't explicitly marked as "virtual"), static calls are
> generated, and thus they are non-virtual. But yes, you're
> right...that's not really accurate, since the language itself
> doesn't
> make the distinction in the _implementation_.


The C# compiler can create two completely different kiinds of code for
mwthods that are not declared virtual. Consider the following file:

namespace Test
{
interface IFace
{
void Doit();
}
class Virtual : IFace
{
public void Doit()
{
}
public void DoitNow()
{
}
}
}

DoitNow is generated as a non-virtual method. Doit is generated as a
virtual method that cannot be overridden. This is completely
transparent to the C# programmer, whether the creator or consumer of
these methods. Presumably it's done this way because a method needs
to be virtual to be part of an interface implementation.

The observstion I'd make here is that virtual vs. non-virtual is
really an implementation artifact. The semantic difference between a
non-virtual method and a virtual method that can't be overridden is
nil (or nearly so.)




Mike Schilling
  Reply With Quote
Old 11-02-2009, 06:40 PM   #45
Wojtek
 
Posts: n/a
Default Re: HashMap get/put
Lew wrote :
> Wojtek wrote:
>> Lew wrote :
>>> FWIW, if 'Map#get()' had been redefined generically, it would have broken
>>> existing code without providing an improvement. Code that would have not
>>> gotten a value still does not get a value without introducing a new error.
>>> Maybe they erred in this, but they were trying to maintain backward
>>> compatibility.

>>
>> All sorts of code broke when generics were introduced. Every use of each
>> class which had generics needed to be changed. Also changing get() would
>> just have been done at that time.
>>
>>> It's a shame that the compiler didn't find your refactoring mistake for
>>> you, but it was your mistake, not Java's.

>>
>> Of course it was my mistake. That is what I am saying. And that is why we
>> have compilers which report mistakes, so that they may be caught BEFORE
>> they show up during runtime and "weird things" happen.

>
> 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. A few minutes with
> the 'Map' Javadocs before you refactored would've saved you some trouble.
> Then you could've used Eclipse's Ctrl-Shift-G (find all references) or the
> equivalent for your IDE and fixed the problem with even less effort than
> letting the compiler find the error would have caused.


Which I did do (eventually). I was initially led astray by an
assumption about generics and how they applied to the Map class.

After all, when you define a (Map<K,V>) you must also instantiate it
the same way (new Map<K,V>). I just assumed that this carried over to
all method calls.

> I think we're spoiled by how much help Java gives us to catch and prevent
> error. We start whining like little brats when we reach one of those corners
> that we have to sweep with our own effort.


Hey look! No red markers! Yeah!

> You did the community a good service by alerting us to this particular
> corner.


<blush>

--
Wojtek




Wojtek
  Reply With Quote
Old 11-02-2009, 08:20 PM   #46
Wojtek
 
Posts: n/a
Default Re: HashMap get/put
Lew wrote :
> Wojtek wrote:
>> Lew wrote :
>>> FWIW, if 'Map#get()' had been redefined generically, it would have broken
>>> existing code without providing an improvement. Code that would have not
>>> gotten a value still does not get a value without introducing a new
>>> error. Maybe they erred in this, but they were trying to maintain
>>> backward compatibility.

>>
>> All sorts of code broke when generics were introduced. Every use of each
>> class which had generics needed to be changed. Also changing get() would
>> just have been done at that time.
>>
>>> It's a shame that the compiler didn't find your refactoring mistake for
>>> you, but it was your mistake, not Java's.

>>
>> Of course it was my mistake. That is what I am saying. And that is why we
>> have compilers which report mistakes, so that they may be caught BEFORE
>> they show up during runtime and "weird things" happen.

>
> 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. A few minutes with
> the 'Map' Javadocs before you refactored would've saved you some trouble.
> Then you could've used Eclipse's Ctrl-Shift-G (find all references) or the
> equivalent for your IDE and fixed the problem with even less effort than
> letting the compiler find the error would have caused.


Which I did do (eventually). I was initially led astray by an
assumption about generics and how they applied to the Map class.

After all, when you define a (Map<K,V>) you must also instantiate it
the same way (new Map<K,V>). I just assumed that this carried over to
all method calls.

> I think we're spoiled by how much help Java gives us to catch and prevent
> error. We start whining like little brats when we reach one of those
> corners that we have to sweep with our own effort.


Hey look! No red markers! Yeah!

> You did the community a good service by alerting us to this particular
> corner.


<blush>

--
Wojtek




Wojtek
  Reply With Quote
Old 11-02-2009, 09:31 PM   #47
Mike Schilling
 
Posts: n/a
Default Re: HashMap get/put
Peter Duniho wrote:
> Mike Schilling wrote:
>> If you look at the method properties using ildasm, you'll see:
>>
>> public hidebysig newslot virtual final instance void Doit() cil
>> managed vs.
>>
>> ..public hidebysig instance void DoitNow() cil managed
>>
>> One has a slot in the virtual table, and one does not.

>
> That's not the point. That's strictly an implementation detail for
> the JIT-compiled output.


Yes, and *that's* the point.




Mike Schilling
  Reply With Quote
Old 11-03-2009, 12:24 AM   #48
Mike Schilling
 
Posts: n/a
Default Re: HashMap get/put
Peter Duniho wrote:
> Mike Schilling wrote:
>> Peter Duniho wrote:
>>> Mike Schilling wrote:
>>>> If you look at the method properties using ildasm, you'll see:
>>>>
>>>> public hidebysig newslot virtual final instance void Doit() cil
>>>> managed vs.
>>>>
>>>> ..public hidebysig instance void DoitNow() cil managed
>>>>
>>>> One has a slot in the virtual table, and one does not.
>>> That's not the point. That's strictly an implementation detail for
>>> the JIT-compiled output.

>>
>> Yes, and *that's* the point.

>
> I suppose that depends on what you're trying to talk about.


The fact that virtual vs. non-virtual isn't a very interesting distinction.
It's really about how calling mechanisms (prior to opimization, which may
make even that moot), not about semantics, because the semantics of "virtual
but final" and "non-virtual" are identical.




Mike Schilling
  Reply With Quote
Old 11-03-2009, 05:40 PM   #49
Robert Klemme
 
Posts: n/a
Default Re: HashMap get/put
On 28.10.2009 23:21, Ken wrote:
> On Oct 28, 4:11 pm, r...@zedat.fu-berlin.de (Stefan Ram) wrote:
>> Wojtek <nowh...@a.com> writes:
>>> All of these are legal according to the compiler. Why is it that the
>>> compiler does not enforce type checking on the get()?

>> Setting with a wrong type can result in a Map that breaks
>> its contract. Therefore, it is forbidden. Getting with a
>> wrong type cannot do such harm, so, it is not forbidden.
>> After all, you can meaningfully and correctly detect at run
>> time that for a wrong key, there is no value in the map.

>
> I don't understand. If the type is not the same as the type used in
> the map there is no chance of success. Clearly this is an error. I'm
> of the mind of the OP.


This is wrong: it solely depends on the implementation of equals() and
hashCode() whether the lookup key needs to be of the same class or not
and consequently whether a lookup can succeed or not.

If you want a practical example: assume a pair of classes MutableLong
and ImmutableLong (not in package java.lang). You implement hashCode()
and equals() in a way that instances with the same long value return the
same hash code and equals() also accepts instances of the other class.
Now you use a MutableLong for all sorts of operations including map
lookups but you use only immutable Long instances as Map keys in order
to avoid issues with key mutation which would make rehashing necessary.

Kind regards

robert

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/


Robert Klemme
  Reply With Quote
Old 11-03-2009, 07:34 PM   #50
Jim Janney
 
Posts: n/a
Default Re: HashMap get/put
Wojtek <> writes:

> Lew wrote :
>> Wojtek wrote:
>>> Lew wrote :
>>>> FWIW, if 'Map#get()' had been redefined generically, it would have
>>>> broken existing code without providing an improvement. Code that
>>>> would have not gotten a value still does not get a value without
>>>> introducing a new error. Maybe they erred in this, but they were
>>>> trying to maintain backward compatibility.
>>>
>>> All sorts of code broke when generics were introduced. Every use of
>>> each class which had generics needed to be changed. Also changing
>>> get() would just have been done at that time.
>>>
>>>> It's a shame that the compiler didn't find your refactoring
>>>> mistake for you, but it was your mistake, not Java's.
>>>
>>> Of course it was my mistake. That is what I am saying. And that is
>>> why we have compilers which report mistakes, so that they may be
>>> caught BEFORE they show up during runtime and "weird things"
>>> happen.

>>
>> 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. A few minutes with the 'Map' Javadocs before you
>> refactored would've saved you some trouble. Then you could've used
>> Eclipse's Ctrl-Shift-G (find all references) or the equivalent for
>> your IDE and fixed the problem with even less effort than letting
>> the compiler find the error would have caused.

>
> Which I did do (eventually). I was initially led astray by an
> assumption about generics and how they applied to the Map class.
>
> After all, when you define a (Map<K,V>) you must also instantiate it
> the same way (new Map<K,V>). I just assumed that this carried over to
> all method calls.
>
>> I think we're spoiled by how much help Java gives us to catch and
>> prevent error. We start whining like little brats when we reach one
>> of those corners that we have to sweep with our own effort.

>
> Hey look! No red markers! Yeah!
>
>> You did the community a good service by alerting us to this
>> particular corner.

>
> <blush>
>
> --
> Wojtek


The javadoc for java.util.Map.get(Object key) is worth reading
carefully here:

More formally, if this map contains a mapping from a key k to a
value v such that (key==null ? k==null : key.equals(k)), then this
method returns v; otherwise it returns null. (There can be at most
one such mapping.)

Note that key and k don't have to be the same type, and it doesn't
even require k.equals(key) -- equals doesn't need to be reflexive. To
me, this looks like a deliberate design choice.

--
Jim Janney




Jim Janney
  Reply With Quote
Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are Off
Pingbacks are Off
Refbacks are Off




SEO by vBSEO 3.3.2 ©2009, Crawlability, Inc.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46