18

In Java, methods are virtual by default; C# is the opposite.

Which is better? What are the advantages and disadvantages in each approach?

Community
  • 1
  • 1
SNA
  • 7,528
  • 12
  • 44
  • 60
  • I would assume it has something to do with the runtime..i am waiting for the answers too +1 – Perpetualcoder Jun 10 '09 at 01:01
  • What is "virtual"? I code in java and I have never hear that before. – OscarRyz Jun 10 '09 at 01:14
  • For Java programmers: http://en.wikipedia.org/wiki/Virtual_function - "virtual" is the qualifier in C++ to allow a subclass to override a (instance) method. Non-static methods in Java are always overrideable (i.e. "virtual" by default), but in C++, the programmer must explicitly declare a method to be virtual in order for a subclass to be able to override it. Also see Virtual Method Table (http://en.wikipedia.org/wiki/Virtual_table). – Bert F Jun 10 '09 at 01:39
  • @Bert F: Ok, so I understand it as "non final". That would be the correct java way to say it isn't? – OscarRyz Jun 10 '09 at 01:45

6 Answers6

42

Anders Hejlsberg: (C# lead architect)

There are several reasons. One is performance. We can observe that as people write code in Java, they forget to mark their methods final. Therefore, those methods are virtual. Because they're virtual, they don't perform as well. There's just performance overhead associated with being a virtual method. That's one issue.

A more important issue is versioning. There are two schools of thought about virtual methods. The academic school of thought says, "Everything should be virtual, because I might want to override it someday." The pragmatic school of thought, which comes from building real applications that run in the real world, says, "We've got to be real careful about what we make virtual."

When we make something virtual in a platform, we're making an awful lot of promises about how it evolves in the future. For a non-virtual method, we promise that when you call this method, x and y will happen. When we publish a virtual method in an API, we not only promise that when you call this method, x and y will happen. We also promise that when you override this method, we will call it in this particular sequence with regard to these other ones and the state will be in this and that invariant.

Every time you say virtual in an API, you are creating a call back hook. As an OS or API framework designer, you've got to be real careful about that. You don't want users overriding and hooking at any arbitrary point in an API, because you cannot necessarily make those promises. And people may not fully understand the promises they are making when they make something virtual.

arul
  • 13,998
  • 1
  • 57
  • 77
  • 6
    Good interview question if I see somone with both Java and .Net in the Resume :) +1 – Perpetualcoder Jun 10 '09 at 01:08
  • Unfortunately, not everyone who designs an API actually puts thought into what should and shouldn't be virtual. I arrived here (as a mostly Java programmer) wanting to understand why my only option to change the behaviour of a single method is to download and modify the source of the entire stack of software that uses the class whose method I want to override. Good answer to the question, though! – Logan Pickup Oct 19 '15 at 19:41
7

Java's way is simpler, C#'s way is more granular, safer and more efficient by default. Which is better is in the eye of the beer holder.

Gerald
  • 23,011
  • 10
  • 73
  • 102
  • 5
    I would argue quite the opposite. Java's is more complex because it has a hidden cost. Virtual methods are not free in both speed and design cost. – JaredPar Jun 10 '09 at 02:12
  • 3
    So do you consider assembly language to be the least complex language to sue? – Gerald Jun 10 '09 at 02:47
  • use* (silly character minimum) – Gerald Jun 10 '09 at 02:47
  • @Gerald, that's a false analogy. You're comparing a high level languages to assembly. I consider virtual methods harder to maintain because you must have a greater understanding of the object hierarchy in order to understand how a method fits into the system. So I consider C# a simpler language to maintain than Java in general because the defaults of the defaults of the language favor maintainability. Just like I favor F# over C# in maintenance because it goes even further in that area with immutable by default. – JaredPar Jun 10 '09 at 03:55
  • @Jared, it was an intentional false analogy in response to your false correlation between hidden costs and complexity. Simpler things almost always have hidden costs. I think it should have been obvious that I was referring to the simplicity of it's usage, not it's maintainability, especially since I made a point of stating that C# was safer. For the record I prefer C# as well, but it's pretty hard to deny that not having to declare something to use it is simpler than having to declare something to use it. – Gerald Jun 10 '09 at 04:36
  • @Gerald, Why do you think hidden costs is not correlated to complexity? I would argue they are strongly correlated especially when you consider the maintenance angle. But yes, having everything be virtual is simpler in that you don't have to think, you just do. – JaredPar Jun 10 '09 at 04:55
  • @Jared, I suppose in the case of maintainability of code with an over-abundance of virtual methods, a case can be made that they're not completely uncorrelated. But it would only be marginally so. Since 9 times out of 10 a method that isn't made virtual to start is perfectly fine to override, the solution is often just to go make it virtual if you need to override it. Maybe you'll look at the code to see if there is a reason it shouldn't be, but you may not know as well as the original author. While if a method is specifically marked as final, it may make you think harder about changing it. – Gerald Jun 10 '09 at 14:48
6

.Net forces the programmer to define which functions may be overriden, whereas Java functions, by default, can be overriden unless the final keyword is used.

If you're a strong advocate of the Open/Close Principle you may tend to support the Java way. It's best to allow classes to be extended and methods to be overriden such that the base functionality/code is untouched. For this reason, I support/prefer the Java way. If I were looking at the question from a different perspective, my opinion may be the opposite.

Elliot
  • 1,286
  • 2
  • 12
  • 22
  • 1
    Well, I'm not sure that C# is not following OCP, since you can add new functionality wrapping public API of original class. Even, I would argue that C# follows OCP more than Java since with Java's virtual by default methods, you're not extending but actually able to CHANGE the original behaviour which is IMHO actually violation of OCP. This is just my opinion :) – dragan.stepanovic Oct 09 '15 at 12:31
4

There are 2 major reasons why virtual by default is so much better than non-virtual.

  1. The main principles about usefulness of OOP is Liskov substitution principle, polymorphism and late binding . I use strategy pattern all the time and for that I want my methods to be virtual. If you are fan of Open/closed principle you should like Java philosophy more. You should be able to change behavior without changing your source code. You can do that with dependency injection and virtual methods.
  2. If you call a non-virtual method then you want to know from your code which class method you are calling. The flaw of .net is that you cannot know that from your code.
  3. Another benefit of virtual-only method is that it is much easier to test your code because you can make Mocks of your (or 3rd party) classes. Testing with Mockito is really easy in Java.

Example

In Java if you define ClassB as

public class ClassB extends ClassA {
    @Override 
    public void run() {
    }
}

and object

ClassA obj=new ClassB();

If you call obj.run() how will you know if that code is following the rules of polymorphic open/close principle or it will code method related to ClassA? In Java you will know that there is always polymorphism. It is easier to make mocks and it is easier to extend classes and follow Liskov substitution principle.

On the other hand static methods are bounded to a class so if you want to call a method that is related to ClassA you can define that method like this:

public static run(ClassA obj)

and you can call it with

ClassB obj=new ClassB();
ClassA.run(obj);

and from the code you will know that the method you are calling is defined in ClassA and not in ClassB. Also in that case you will not have the overhead of virtual methods. (Note that JIT will also reduce the overhead of virtual methods in many cases).

For C#, if the reason to make the method non-virtual is to be able to define it in a subclass but not involve polymorphism, you're probably subclassing for no real reason.

If it's for design, I'd suggest making the class sealed (final in java) instead of individual methods if possible.

Jon Skeet said that in C# the classes should be sealed by default because methods are non-virtual by default as well. Joshua Bloch said that you should design for inheritance or forbid it (make classes final). C# designers chose a hybrid approach which is non-consistent.

user1944408
  • 509
  • 3
  • 12
  • Downvoter, explain please? You might be right downvoting but I would like to learn about your position and possibly agree with that. Thanks :) – user1944408 Feb 19 '14 at 14:10
2

It's a perturbation in time. C++ uses the virtual keyword and final as default.

Java follows C++ and attempts to take the best and improve on its shortcomings. The dangers of overuse of inheritance haven't come to light, so Java chooses to use the final keyword and virtual as default.

C# follows Java and has the benefit of hindsight. Anders chooses to go back to the C++ convention after observing Java's experience.

duffymo
  • 305,152
  • 44
  • 369
  • 561
1

As always, there are pros and cons. C# has made AOP more difficult to implement, but hindsight can be 20/20 as mentioned by others. It all boils down to whether or not you believe that classes must be designed for extension or simply left open for unforeseen behavior modifications. When designing a language, this is a tough question to answer. I think industry experience is leaning towards the more conservative approach that C# takes.

Todd Stout
  • 3,687
  • 3
  • 24
  • 29