F Sharp Programming/Inheritance

Many object-oriented languages use inheritance extensively in the .NET BCL to construct class hierarchies.

Subclasses
A subclass is, in the simplest terms, a class derived from a class which has already been defined. A subclass inherits its members from a base class in addition to adding its own members. A subclass is defined using the  keyword as shown below:

Our simple class hierarchy looks like this: System.Object (* All classes descend from *) - Person - Student - Worker

The  and   subclasses both inherit the   and   methods from the   base class. This can be demonstrated in fsi:

.NET's object model supports single-class inheritance, meaning that a subclass is limited to one base class. In other words, its not possible to create a class which derives from  and   simultaneously.

Overriding Methods
Occasionally, you may want a derived class to change the default behavior of methods inherited from the base class. For example, the output of the  method above isn't very useful. We can override that behavior with a different implementation using the :

We've overridden the default implementation of the  method, causing it to print out a person's name.

Methods in F# are not overridable by default. If you expect users will want to override methods in a derived class, you have to declare your method as overridable using the  and   keywords as follows:

Our class  provides a   method which may be overridden in derived classes. Here's an example of these two classes in fsi:

Abstract Classes
An abstract class is one which provides an incomplete implementation of an object, and requires a programmer to create subclasses of the abstract class to fill in the rest of the implementation. For example, consider the following:

The first thing you'll notice is the  attribute, which tells the compiler that our class has some abstract members. Additionally, you notice two abstract members,  and   don't have an implementation, only a type signature.

We can't create an instance of  because the class hasn't been fully implemented. Instead, we have to derive from  and override the   and   methods with a concrete implementation:

Now we have several different implementations of the  class. We can experiment with these in fsi:

Up-casting and Down-casting
A type cast is an operation which changes the type of an object from one type to another. This is not the same as a map function, because a type cast does not return an instance of a new object, it returns the same instance of an object with a different type.

For example, let's say  is a subclass of. If we have an instance of, we are able to cast as an instance of. Since  is upward in the class hierarchy, we call this an up-cast. We use the  operator to perform upcasts:

Up-casting is considered "safe", because a derived class is guaranteed to have all of the same members as an ancestor class. We can, if necessary, go in the opposite direction: we can down-cast from an ancestor class to a derived class using the  operator:

Since  holds an   boxed as an , we can downcast to an   as needed. However, we cannot downcast to a  because it is an incompatible type. Down-casting is considered "unsafe" because the error isn't detectable by the type-checker, so an error with a down-cast always results in a runtime exception.

Up-casting example
This program has the following types:

This program outputs: x.ToString: Circle, area = 78.539816 x.ToString: Circle, area = 452.389342 x.ToString: Square, area = 110.250000 x.ToString: Triangle, area = 6.000000 x.ToString: Rectangle, area = 10.000000