Non-virtual methods - why?

  • Thread starter Thread starter Adrian Herscu
  • Start date Start date
Think again. *Only* non-virtual methods can be "hidden".
Not sure where you get that from:

using System;

class Base
{
public virtual void Foo()
{
Console.WriteLine ("Base.Foo");
}
}

class Derived : Base
{
public new void Foo()
{
Console.WriteLine ("Derived.Foo");
}
}

public class Test
{
static void Main()
{
Base b = new Derived();
Derived d = new Derived();

b.Foo();
d.Foo();
}
}

Base.Foo is clearly a virtual method, but as far as I can see
Derived.Foo hides it in exactly the same way as if it were non-virtual.
Take away the keyword "new" and you get a warning:

Base::Foo is clearly declared virtual, but it is not really virtual !
If it were virtual then:

Base b = new Derived();
b.Foo();

would output:

Derived.Foo

That's exactly the semantics of being non-virtual.

And again, "final" in Java is very different from non-virtual - a
non-virtual method can be hidden, but a "final" method cannot be hidden.
 
Adrian Herscu said:
Base::Foo is clearly declared virtual, but it is not really virtual !

Yes it is. You could create another class which overrides it, and that
would be called if you had:

Base b = new OtherDerived();
b.Foo();

A virtual method doesn't have to actually have *been* overridden to be
virtual.
If it were virtual then:

Base b = new Derived();
b.Foo();

would output:

Derived.Foo

No, that's what would happen if Derived.Foo overrode Base.Foo. It
doesn't, but that's because of Derived.Foo hiding Base.Foo, not because
Base.Foo isn't virtual in the first place. How can the presence or
absence of another method change whether or not a method is virtual?
That's exactly the semantics of being non-virtual.

Nope. The semantics of being non-virtual is that the method can't be
overridden.
And again, "final" in Java is very different from non-virtual - a
non-virtual method can be hidden, but a "final" method cannot be hidden.

But a virtual method can't be hidden either in Java! Whether or not a
method is virtual or not has *nothing* to do with whether or not the
language supports hiding.
 
Hi,

Jon said:
In modern Java VMs (or at least HotSpot), methods are actually treated
as non-virtual until they are overridden, whereupon code which calls
the overridden method is rejitted to make a virtual call. Of course,
this trickery may well have been included only because so many methods
in Java *are* virtual, but I still think it's important to note.

So if you need that extra performance (but I can't think of a good reason
why you would), you have to try and guess what the Java jitter is going to
do?

Interesting that he says virtual and override say different things.. I
hadn't thought of it that way before.

-- Pete
 
Pete said:
So if you need that extra performance (but I can't think of a good reason
why you would), you have to try and guess what the Java jitter is going to
do?

Not really - it's not like you have to change your code to take
advantage of it. Knowing what the JIT is capable of (and its
limitations) is likely to help though - and that's not unique to Java
by any means. It's a bit of a chicken-and-egg situation. The more you
know about how any one implementation of the CLR or Java VM works, the
better you're likely to be able to write code for that particular
archiecture - but what's good for one might be awful for another. For
instance, with one garbage collector and heap allocator, object pooling
could be a really good idea; with another, it might be something to
avoid.
Interesting that he says virtual and override say different things.. I
hadn't thought of it that way before.

I'm not exactly sure about which bit you mean, but yes - it's generally
good stuff.
 
1.
A virtual method has to execute the same implementation, no matter through
which interface it was invoked.
And in your example, it does matter.

IMHO, the "virtual" term is not about declarations, it's about behavior. So,
if a method doesn't behave as "virtual", then it is not virtual.

At the end, (in C#) it depends on the direct subclass if a declared virtual
method is actually virtual.
And this is a fundamental difference between C# and the others (C++ and
Java):
In C++, a declared virtual method will always be overridden by a subclass
owning a method with the same signature.
In Java all non-finalized instance methods are virtual.

2.
Consider this:

using System;

class Base {
static private void DoBaseFoo() { Console.WriteLine("Did Base Foo"); }
public void Foo() { DoBaseFoo(); }
}

class Derived : Base {
static private void DoDerivedFoo() { Console.WriteLine("Did Derived
Foo"); }
new public void Foo() { DoDerivedFoo(); }
}

class TestNonVirtual {
static public void Main() {
Object d = new Derived();

((Base)d).Foo(); // This will execute DoBaseFoo()
((Derived)d).Foo(); // and this will execute DoDerivedFoo().

/*
That is because Base::Foo is non-virtual not only by
declaration,
but also by behavior.
*/
}
}

Can you build such a thing in Java? If you can, then Java supports
non-virtual methods.
 
Sounds like programmers will develop dependence on some particular
implementation.
As a driver, I don't care if my car engine has a central-point injection or
multi-point injection system - I will use it the same way!
 
Adrian Herscu said:
1.
A virtual method has to execute the same implementation, no matter through
which interface it was invoked.
And in your example, it does matter.

Only because the virtual method doesn't enter into it - the hiding
method means that it's called instead of a virtual call being made.
That has nothing to do with whether or not the base method is virtual.
IMHO, the "virtual" term is not about declarations, it's about behavior. So,
if a method doesn't behave as "virtual", then it is not virtual.

I disagree entirely. A method doesn't just "become" virtual due to
having been overridden elsewhere. A method is virtual if it *can* be
overridden. That's all there is to it. Note that you're also
disagreeing with the C# language specification here, which says:

<quote>
When an instance method declaration includes a virtual modifier, that
method is said to be a virtual method.
</quote>

Do you at least agree, given that your above, that your idea of a
method being virtual is not the same as the C# language specification's
idea?
At the end, (in C#) it depends on the direct subclass if a declared virtual
method is actually virtual.

No it doesn't - because otherwise you've got the situation where it's
half-virtual and half-not-virtual, if it's overridden in one class and
hidden in another.
And this is a fundamental difference between C# and the others (C++ and
Java):
In C++, a declared virtual method will always be overridden by a subclass
owning a method with the same signature.
In Java all non-finalized instance methods are virtual.

Which means that finalized instance methods are non-virtual, as I said
before and which you disagreed with.
2.
Consider this:

using System;

class Base {
static private void DoBaseFoo() { Console.WriteLine("Did Base Foo"); }
public void Foo() { DoBaseFoo(); }
}

class Derived : Base {
static private void DoDerivedFoo() { Console.WriteLine("Did Derived
Foo"); }
new public void Foo() { DoDerivedFoo(); }
}

class TestNonVirtual {
static public void Main() {
Object d = new Derived();

((Base)d).Foo(); // This will execute DoBaseFoo()
((Derived)d).Foo(); // and this will execute DoDerivedFoo().

/*
That is because Base::Foo is non-virtual not only by
declaration,
but also by behavior.
*/
}
}

Can you build such a thing in Java? If you can, then Java supports
non-virtual methods.

No, but I don't *need* to for Java to support non-virtual methods. I
repeat, hiding is *not* a necessity for non-virtual methods to be
supported.

As you said before:
"In Java all non-finalized instance methods are virtual."

So what are finalized instance methods? Are they virtual or are they
not, according to your understanding?
 
I agree on that there are multiple perspectives.
About specs in general - they are not holly scripts (yet).

Anyway, the original question was: "In which circumstances it is appropriate
to declare methods as non-virtual?".

I read Anders' interview, and the answer to the above question is burried
somewere in.

Thank you all,
Adrian.
 
You don't *have* to be able to hide them in order for them to be non-
virtual though! Hiding's just a different concept in the same area.


Not really, because there's a warning message if you try to do it.
Imagine tha you' ve got a class framework from third party
tha class is something like

class Foo: FooBase
{
new public virtual string ToString()
{
....
}
}

class Bar: Foo
{
public override string ToString()
{
.....
}
}


You desided to inherit from Bar

class MyBar: Bar
{
public override string ToString()
{
}
}


Then
object obj = new MyBar()
Console.WriteLine(obj); //result is FooBase's base ToString();

How hard is to find what is going on here?
In my class I override a method which is declared as a virtual in the Object
class and is overriden in my base class. How could I know that it is has
been hidden in some of my base's base classes.

Before you start arguing that noone will hide ToString() I'll tell you that
is true because noone will hide any virtual method. Otherwise I don't want
to be progammer using one's framework. or class library.
Which both C# and Java have.


I disagree with this - a warning is all that's required to avoid
hiding. Sealing an otherwise virtual method makes it non-virtual, and
that's all that's required.

Yes, the warning will warn me and I'll use the *new* keyword to make the
compiler happy. What about the others that will inherit my class and will
struggle to find why their code doesn't work as expected with virtual
methods.
I don't think that was the reason at all. I think it was to prevent
classes from breaking when they're recompiled against newer versions of
libraries they may use. You get a warning if you try to hide a member
(because the member may not have existed before), but you get the same
behaviour, and can remove the warning by explicitly saying that that's
what you wanted to do. Don't forget that this method may itself be part
of a public API which can't easily be changed.

Frankly I didn't get that.

Let imagine for a sec that there wasn't *publi virtual string ToString()*
method in Object class. I've needed it so I've added *public string
ToString()* method in my class.

You are trying to tell me that if later they add *public virtual string
ToString()* method in the Object class I'll put a new keyword infornt of my
ToString implemetation.

Rather I'll put *override* for that ToString method of mine. And I don't see
any case where one will put *new*. I don't see how my class introducing new
implementation of ToString will work correctly with the rest of the classes
in the framework.

Brgds
100
 
Adrian Herscu said:
Sounds like programmers will develop dependence on some particular
implementation.
As a driver, I don't care if my car engine has a central-point injection or
multi-point injection system - I will use it the same way!

In a normal case that is true. But as programmers we are often pushing the
limits. We sometimes need to know the internals to get the performance we
need even if that means the application is less portable.

To give you a car example:

I drive a Subaru WRX, it's all wheel drive with a fairly sophisticated
system for distributing engine torque to the wheels. No normal person needs
to know this to drive the car. In fact you don't even need to know it's all
wheel drive. However I depend on this particular implementation since my
normal application (going up my driveway in the winter) is beyond what a
typical two wheel drive implementation can do.
 
Imagine tha you' ve got a class framework from third party
tha class is something like

Then
object obj = new MyBar()
Console.WriteLine(obj); //result is FooBase's base ToString();

How hard is to find what is going on here?

Well, it's not hard when you've seen it happen, of course, but I take
your point.
In my class I override a method which is declared as a virtual in the Object
class and is overriden in my base class. How could I know that it is has
been hidden in some of my base's base classes.

As far ass I know, you can't - and yes, that's a problem.
Yes, the warning will warn me and I'll use the *new* keyword to make the
compiler happy. What about the others that will inherit my class and will
struggle to find why their code doesn't work as expected with virtual
methods.

One thing to do of course is document everything. Don't forget that
most methods *shouldn't* be virtual. I think it *would* be rare to hide
one virtual method with another virtual method. All three of "methodn
in base class is virtual", "method in derived class is virtual",
"method in derived class hides method in base class" should be rare.
And then, yes, you've got a problem.
Frankly I didn't get that.

Let imagine for a sec that there wasn't *publi virtual string ToString()*
method in Object class. I've needed it so I've added *public string
ToString()* method in my class.

You are trying to tell me that if later they add *public virtual string
ToString()* method in the Object class I'll put a new keyword infornt of my
ToString implemetation.

If you want behaviour to stay the same, you should, yes.
Rather I'll put *override* for that ToString method of mine. And I don't see
any case where one will put *new*.

In that case a lot of your code may well break. Developers who only
know about the base class may well call the method, requiring very
different semantics from those that your class provides. You may well
have documented that your method should only be called in certain ways,
for instance - and suddenly it's being called in other ways due to
overriding the base class method.
I don't see how my class introducing new
implementation of ToString will work correctly with the rest of the classes
in the framework.

But that's the point - the things which knew about your ToString method
before will still call it, and the things which didn't won't - which is
usually what you want.
 
Back
Top