Re: HashMap get/put
Mike Schilling wrote:
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.
Well, you are using the same semantics I am. But as I pointed out,
there's room for confusion here.
A call to DoitNow() still generates a "callvirt" MSIL instruction
(similar to the Java approach). And in fact, you can change the
implementation of your class Virtual so that DoitNow() is virtual and,
after recompiling the assembly containing that class, a call site for
the DoitNow() method in a completely different assembly will still work
properly without itself being recompiled.
For example:
Assembly1.dll:
namespace Test
{
interface IFace
{
void Doit();
}
class Virtual : IFace
{
public void Doit()
{
}
public void DoitNow()
{
}
}
class Derived : Virtual
{
}
}
Program.exe:
namespace Test
{
class Test
{
public void Method()
{
Derived d = new Derived();
d.DoitNow();
}
}
}
In the above, Virtual.DoitNow() is what's called in Test.Method(). But,
change DoitNow() to be virtual, add an override in Derived, and then
rebuild Assembly1.dll. Without touching Program.exe, you still get the
virtual method's override in Derived, because the call site is
"virtual", whether the method is declared as "virtual" or not.
This is the behavior Thomas is talking about, and which is different
from the context in which I'm describing the method as "virtual" or "not
virtual". In particular, as far as the MSIL is concerned, _all_ method
calls are "virtual" in the sense that there's essentially a vtable (not
really, but that's how it looks in MSIL).
Doit is generated as a
virtual method that cannot be overridden.
Sort of. It can be overridden if the original implementation is also
declared as virtual. The question of whether it can be overridden or
not isn't inherent to the implementation but rather is just a language
restriction (similar to accessibility restrictions).
> 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.
Yes, sort of. I agree with your description, but it's in conflict with
the way Thomas and Patricia are talking about "virtual". In the respect
of their comments, the method needs to be virtual because _all_ visible
methods are virtual. The fact that it's an interface method doesn't
really play a part. The method would be "virtual" regardless.
Now, once the JIT compiler gets ahold of the code, the interface method
will (most likely, barring further optimization) remain virtual, called
through an actual vtable-like data structure, while other "non-virtual"
methods can be compiled as statically resolved call sites.
It's this latter characteristic of "virtual" that I was thinking of, but
that wasn't the correct point of view given what Patricia meant.
The observstion I'd make here is that virtual vs. non-virtual is
really an implementation artifact.
That really depends on which meaning of "virtual" you're talking about.
Personally, I tend to look at the exposed language side, or the
deepest implementation side (i.e. the native code). In both of those
contexts, a method is either virtual or not. It may be virtual
explicitly (because it's declared that way) or implicitly (because it's
part of an interface). To me, the important thing is that you get the
polymorphic behavior that arises from virtual methods.
In retrospect, reading that previous sentence I wrote, I suspect that my
view is a carry-over from C++. Maybe it's not all that appropriate in
the context of Java or C#, but I hold it nevertheless. :)
Anyway...
The point here is that Thomas and Patricia are looking not at the
surface of the language, nor the final native implementation of the
code, but rather what the syntax in the language represents in the
context of the virtual machine that is expected to execute the code.
This isn't an unreasonable view. After all, the syntax of the language
is just veneer, a way for us to express more simply the things we want
the actual computer to do. And in Java the virtual machine _is_ the
"computer" that we're instructing in this case; the actual native
instruction set is just an optimization (and in fact, in Java the byte
code may never wind up being compiled to native, just being interpreted
instead).
In that view, the "virtual vs. non-virtual" is (as Thomas and Patricia
point out) a non-existent distinction. If it exists at all, it
necessarily must be an "implementation artifact".
As I said, that's not really the view I'm taking when I wrote about
"virtual". From the syntactical point of view, I think there really is
a difference between methods that are virtual and those that aren't.
That is, a method is virtual if it can behave polymorphically and it's
not if it can't. And in Java, we call the latter type "final". :)
But I at least see why Patricia wrote what she did, and I don't disagree
with it, now that I understand the context in which the statement was
intended to be understood.
The semantic difference between a
non-virtual method and a virtual method that can't be overridden is
nil (or nearly so.)
IMHO, it's a very strong semantic difference at the language level.
It's what allows interfaces to have the same polymorphic behavior that
virtual methods provide. With a non-virtual method ("final" in Java,
just not "virtual" in C#), if you have an instance of the type in which
that method is declared, you always get the implementation in that type.
Period. But for a method declared in an interface, you can get any
variety of implementations, depending on the actual implementor of the
interface.
So, sure...unless the implementor has declared the implementation as
"virtual" explicitly, sub-classes can't override it. But it's still
providing the (IMHO vastly more) powerful feature of polymorphism. I
consider that a pretty significant "semantic difference". :)
Pete