Why all java methods are implicitly overridable?
Asked Answered
H

6

21

In C++, I have to explicitly specify 'virtual' keyword to make a member function 'overridable', as there involves an overhead of creating virtual tables and vpointers, when a member function is made overridable (so every member function is implicitly not overridable for performance reasons).

It also allows a member function to be hidden (if not overridden) when a subclass provides a separate implementation with the same name and signature.

The same technique is used in C# as well. I am wondering why Java waved away from this behavior and made every method overridable by default and provided the ability to disable overriding behavior on explicit use of 'final' keyword.

Hermineherminia answered 7/5, 2009 at 19:56 Comment(1)
Be sure to read #815434 .Tao
A
27

The better question might be "Why does C# have non-virtual methods?" Or at the very least, why aren't they virtual by default with the option to flag them as non-virtual?

In C++, there is the idea (as Brian so nicely pointed out) that if you don't want it, you don't pay for it. The problem is that if you do want it, this usually means you end up paying through the nose for it. In most Java implementations, they are designed explicitly for lots of virtual calls; the vtable implementations tend to be fast, scarcely more expensive than non-virtual calls, meaning the primary advantage of non-virtual functions is lost. Furthermore, JIT compilers can inline virtual functions at runtime. As such, for efficiency reasons, there is very little reason actually to use non-virtual functions.

Thus, it largely comes down to the principle of least surprise. It tells us that all methods to behave the same way, not half of them being virtual and half of them being non-virtual. Since we need to have at least some virtual methods to achieve this polymorphism thing, it makes sense to have them all be virtual. Furthermore, having two methods with the same signature is just asking to shoot yourself in the foot.

Polymorphism also dictates that the object itself should have control over what it does. It's behavior should not be determinate on whether the client thinks it's a FooParent or a FooChild.

EDIT: So I'm being called on my assertions. This next paragraph is conjecture on my part, not a statement of fact.

An interesting side effect of all this is that Java programmers tend to use interfaces very heavily. Since the virtual method optimizations make the cost of interfaces essentially non-existent, they allow you to use a List (for example) instead of an ArrayList, and switch it out for a LinkedList at some later date with a simple one-line change and no additional penalty.

EDIT: I'll also pony up a couple sources. While not the original sources, they do come from Sun explaining some of the workings on HotSpot.

Inlining

VTable

Alnico answered 7/5, 2009 at 20:23 Comment(6)
You're making a lot of assumptions and over-generalizing. Care to back any of your assertions up? How insulting to Java programmers to tell them that their diligent programming practices as a communuity (e.g. using interfaces) evolved from Java's blindingly quick vtable method invocation. While your argument sounds compelling, it's a load of rubbish. Only fools care about the micro-optimization of virtual versus non-virtual invocation. If you were that worried about speed you wouldn't use Java. I call BS.Unconventionality
I think it's more insulting to say that Java programmers don't care about speed. The Sun Java implementation tends to be about as fast as C++ implementations, give or take depending on the task. One of the advantages of Java is that we don't have to worry about micro-optimizations like this: the compiler and JIT compiler are smart enough to do most of them for usAlnico
If speed is important, you should stick to plain C. :-)Burrussburry
@James, the only thing I was insulting was your assertion. Compiler, JIT'er, what's the difference to you? It's all a black box that someone else programmed. Are you saying C++ programmers do micro-optimise in such a fashion? I've never seen it. Unless you're writing compilers, nobody cares. What Java does is a very different answer from why it does it.Unconventionality
If speed is important, you should stick to asm. :-) (Or better yet, verilog/vhdl and dump it to an FPGA.)Gisborne
@Gisborne Or even better design an ASIC to do the job. If speed is important, why not hard code everything :P Get your point though. People tend to write functions with 30 lines or more far too often and inside of some functions there are gigantic for loops. Why bother that much saving 25 % of the time of a function call (Stroustrup, Bjarne, The c++ programming language) even in C++ if it is not absolutely necessary?Chronicles
C
19

Taken from here (#34)

There’s no virtual keyword in Java because all non-static methods always use dynamic binding. In Java, the programmer doesn’t have to decide whether to use dynamic binding. The reason virtual exists in C++ is so you can leave it off for a slight increase in efficiency when you’re tuning for performance (or, put another way, "If you don’t use it, you don’t pay for it"), which often results in confusion and unpleasant surprises. The final keyword provides some latitude for efficiency tuning – it tells the compiler that this method cannot be overridden, and thus that it may be statically bound (and made inline, thus using the equivalent of a C++ non-virtual call). These optimizations are up to the compiler.

A bit circular, perhaps.

Cogent answered 7/5, 2009 at 19:58 Comment(4)
confusion and unpleasant surprises?Hermineherminia
e.g. Non-virtual base::foo(), you have class derived: public base. You add derived::foo(), do a base *d = new derived(); d->foo(); and it calls base::foo instead of derived due to the static type of the pointer.Parapsychology
Circular indeed, but all that means is that it was a design choice. The question then becomes why would they choose it? Java has a complex run-time system (the VM), and having all method calls be dynamically dispatched is a simplifying choice. When C++ code is compiled there is no run-time, the the program is the whole system and making a always-dynamic assumption wouldn't make the resulting machine code any simpler because the call logic is just replicated all over the place as needed.Hards
That statement is incorrect, Java does not always use dynamic binding. It is in fact only used for overloaded methods, overridden ones are statically bound at compile time.Caboose
S
11

So Java's rationale is probably something like this: the whole point of an object-oriented language is that things can be extended. So in terms of pure design, it really makes little sense to treat extensible as the "special case".

Remember that Java has the luxury of compiling at runtime. So some of the performance arguments in C++ compilation go out the window. In C++, if a class might be overridden, then the compiler has to take extra steps. In Java, there's no mystery about it: at any given moment in time, the JVM knows whether or not a particular method/class has been overridden or not, and that's essentially what counts.

Note that the final keyword is essentially about program design, not optimisation. The JVM doesn't need this information to see whether or not a class/method has been overridden!!

Sophister answered 7/5, 2009 at 21:32 Comment(2)
"The JVM doesn't need this information to see whether or not a class/method has been overridden". Although with class loading, a JVM which treats a non-final method as final because it happens not to be overridden yet, needs a way to change that later. Sure, smarter JVMs presumably can do this, and can go back and rewrite non-virtual calls to virtual ones when it loads a new subclass. But I can empathise if the language designers didn't want to count on that.Leprosarium
Yes, I'm taking for granted that the JVM can recompile as you say. Sun's JVM does; I'm assuming any other JVM that you'd run moderately performance-critical applications on would also be able to. I'll concede that there are probably some simpler JVMs knocking about, e.g. on (older?) mobile devices, that may actually make optimisations based on 'final'.Sophister
B
3

If the question is about to ask what is the better approach between java and C++/C# then it was already discussed in opposite direction in another thread, and many resource available on the net

Why C# implements methods as non-virtual by default?

http://www.artima.com/intv/nonvirtual.html

Recent introduction of @Override annotation and its wide adoption in new code, suggest that the exact answer to the question "Why all java methods are implicitly overridable?" is indeed because the designer made a mistake. (And they already fixed it)

Oh ! I'm going to get negative vote for this.

Bio answered 8/5, 2009 at 3:31 Comment(1)
@Override is as much to ensure you actually override the method, and don't fail to by mistake, as it is to ensure that you only override on purpose.Hint
H
1

Java tries to move closer to a more dynamic language definition, where everything is an object and everything is a virtual method. It also wants to avoid ambiguity and hard to understand constructs, which it's designers viewed as a flaw in C++, therefore no operator overloading, and in this case no ability to have two public method signatures on one class hierarchy invoking different methods depending on the type of the variable referencing it.

C# is more concerned about the stability of subclasses and making sure that the subclasses behave predictably. C++ is concerned about performance.

Three different design priorities, leading to different choices.

Hint answered 7/5, 2009 at 20:39 Comment(0)
H
1

I would say that in Java cost of virtual method is low compared to whole VM costs. In C++ it is significant cost, compared to assembly-like C background. Nobody would decide to make all methods called through pointer by default as result of C to C++ migration. It's too big change.

Hindu answered 8/5, 2009 at 8:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.