#1697 Final, virtual, override

jodastephen Sun 13 Nov 2011

In writing up Fantom, I was reminded of my dislike for having to define slots as virtual in order to allow them to be overridden (in the code I write in Java I hardly ever use final outside of immutable classes). But I then realised that there is a more challenging disconnect with classes in Fantom.

A class is always virtual, and has to be declared final.

A slot is always final and has to be declared virtual.

This conflict of design looks wrong to me. I'd also note that declaring one method abstract requires the class to be abstract.

Thus, I'd like to see the tension resolved one way or the other. Either

  • slots are virtual by default and have to be declared final, or
  • classes are final by default and have to be declared virtual

My choice would be the former, but I could understand the latter. The situation right now is just weird.

DanielFath Sun 13 Nov 2011

While it does somewhat ruin the principle of least astonishment I think that justification for performance reasons is enough. I guess. If that happens I kinda lean toward latter though Java-way(tm) sounds good enough.

MoOm Sun 13 Nov 2011

I really like the "non-virtual by default" policy of Fantom, as it forces you to think about which methods can be safely overridable when you design a class. It also auto-documents the API, so if I want to implement my own fwt::Widget, I directly know which methods I should override to customize the behavior of the component.

About the "final class by default" idea, I don't see a good reason to do that. Inheriting from a class is never a dangerous thing to do (contrary to overriding a method), so I don't think we should forbid it by default.

qualidafial Sun 13 Nov 2011

I would prefer non-virtual classes and slots be the default.

It's true this would be more consistent, but more importantly, it is forward-compatible.

A final class can be made virtual without breaking existing code. However, a virtual class cannot be made final once the code is released.

Likewise, a final method can be made virtual without breaking existing code, but a virtual method cannot be made final.

With virtual by default: that method that you forgot to make final before release? It's too late now, people are already extending it even though your class wasn't designed to be used that way. It's stuck that way now forever.

Classes intended for extension should be explicitly designed for extension.

Virtual by default is a great way to make sure our design mistakes live forever as deprecated APIs. :)

helium Sun 13 Nov 2011

By "virtual class" you mean a class that can be subclassed? Because AFAIK Fantom doesn't have virtual classes as they are commonly known (i.e. you can override member classes in subclasses of the outer class, a very rarely seen feature).

The current situation in Fantom is the same as in C# (and C++). But I'd have no problem with classes being sealed by default.

qualidafial Sun 13 Nov 2011

I'm using virtual as the opposite of final.

brian Sun 13 Nov 2011

I followed C# here, which I think was based on very solid reasoning:

Overriding methods is used to change behavior. Unless the class was explicitly designed for this, you have no idea how those methods are used by the class internals. Something may work in one release and change in the next. I think in the world of open source, you can look inside the class and probably figure out what is safe to override. But in closed source you just have no idea. So overriding behavior is dangerous and we force developers to explicitly design their override points with virtual keyword. I continue to be surprised by anyone who would ever be against this design (unless of course you spend most of your time working with open source).

Creating subclasses is really just a form of sub-typing. It is rarely dangerous because you aren't changing existing behavior, just creating new behavior. So I don't see much harm in making it allowable by default. That said, I've come to see OO sub-classing and whole inheritance thing as something to use as "last resort" in your design. It usually creates complexity. So if doing it over again, I'd definitely favor making classes final/sealed by default.

But this is really water under the bridge - I think it is too late be revisiting design decisions like this one. This would be a really big breaking change, and as such would have to be really compelling and have fairly unanimous community support.

Login or Signup to reply.