Hacker News new | past | comments | ask | show | jobs | submit login

Virtual dispatch always has a cost, it's "free" in Java in the sense that it's always done at the VM level, so you might as well just use it, even final methods are just an agreement with the compiler, the VM doesn't care, it will dynamically look up the method in the class hierarchy like God intended. C++ makes it painful and obvious what you're getting yourself into.

The JVM is off course very clever and is, I'm sure, doing tons of shenanigans to reduce the cost, but that's not free, that's someone else investing tons of time and effort and complexity to reduce the cost of a fundamentally expensive operation.




> even final methods are just an agreement with the compiler, the VM doesn't care, it will dynamically look up the method

You’re right about the “final” keyword being a placebo, but you got the rest exactly backwards.

The JVM is ridiculously aggressive in optimizing for throughout over latency: It assumes that everything is final and compiles the code with that assumption until proven otherwise. If it sees a method getting overridden, it will go back and recompile all the callers and everything that was incorrectly inlined.

A lot of Java code depends on this. For example if you only load one of several plugins at runtime, there’s no overhead vs implementing that plugin’s feature in the main code base.


A single plugin case is a kinda optimistic wishful thinking. Sure, this case happens. Sometimes.

But in real code you often have plenty of things like iterators or lambdas, and you'll have many of types of those. So the calls to them will be megamorphic and no JVM magic can do anything about it.

While in C++ world you'd use templates or in Rust you'd use traits, which are essentially zero cost, guaranteed.


>While in C++ world you'd use templates or in Rust you'd use traits, which are essentially zero cost, guaranteed.

Templates create more code

If the code becomes too large to fit in the cache, it becomes very slow


Somehow I never noticed it happening in practice. In all the cases where cache was the problem, it was caused by data, not code. CPUs prefetch the code into cache quite well.


Are you talking about type erasure and generics? If so I agree, but that’s unrelated to devirtualization


They are kinda related in a way that Java implementation of generics does not help with devirtualization, while C++ templates / Rust traits do help by not needing virtual calls from the start.

Consider the pre- Java 1.5 sort method:

Collections.sort(List list, Comparator comparator);

If you load more than one Comparator type, then the calls to comparator are megamorphic and devirtualization won't happen unless the whole sort is inlined.

In languages like C++, you'd make it a template and the compiler would always know the target type, so no need for virtual.


Default virtual was among the dumber design mistakes in Java, but it has lots of competition.


Why? The JVM has complete knowledge over the entire code base at runtime. It knows which methods require virtual function calls and which ones are just regular function calls. If nothing extends the class, then there will be no virtual functions in the entire class. If something extends the class but it does not override any methods then there again will be no virtual functions. If a class overrides a single method, only that method is going to be a virtual function.


See my reply to the GP. Default virtual is the only thing that makes sense given how the JVM works.


You understand the JVM was designed at the same time as the language? It could work any way they liked. And does.


Sure, but if you have the same preferences (throughout over latency), you’ll find that there are no performance benefits to be gained from non-virtual functions in any JITed language. The “final” keyword is just there for documentation.


Virtual or not isn't about performance, it is about system architecture. Virtual is structurally about implementation. Exactly to the degree that the public interface matches the inheritance interface, the abstraction is a failure.

At least, if you are being object-oriented, which Java tries to force on you. Of course, you are free to violate that expectation, and sometimes must since Java offers no other means of organization; so if you do, more power to you.




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: