F#22 : Abstract classes / Overriding Methods / Implementing Interfaces

In this article we continue the OO leg of our F# journey. So this time we will look at abstract classes / overriding methods and how to implement interfaces

 

Abstract Methods / Virtual Method

F# like the rest of the .NET languages allow you to mark a method (function) as abstract. There is a subtle difference in that you must declare a member as abstract even you do not supply a default implementation. You can kind of think as abstract methods with no default implementation as a abstract method, and a abstract member with a default implementation as a virtual member. There is no virtual keyword in F#.

In order to have a pure abstract method (that is one with no default implementation) you need to use the special AbstractClass attribute, otherwise you will get a compile time error

 

image

Let’s ignore this for now and concentrate on some working code:

 

Virtual Methods

Here is  an example of an abstract method that has a default implementation(which is achieved using the default keyword), which is the equivalent of a virtual method in C#, here is an example of this:


type SomeBaseClass() =
    let mutable z = 0
    abstract member SomeVirtualMethod : int -> int
    default this.SomeVirtualMethod(a : int) = 
        z <- z + a 
        z

type SomeDerivedClass() =
    inherit SomeBaseClass()
    override this.SomeVirtualMethod(a: int) = a * 2

It can be seen that in the SomeDerived class we can override the base implementation by using the override keyword, which works much the same as it does in any other .NET languages, you are selectively choosing to provide a new implementation for the method you are overriding. What is quite different in F# is that you lack some of the finer points of say C#, such as

  • Using the “new” keyword to hide an implementation of  a particular method
  • Calling into the original base class method in an overridden method

Here is an example of a virtual method in use:

let foo = new SomeDerivedClass()
printfn "foo.SomeVirtualMethod(24) %A" (foo.SomeVirtualMethod(24))
 

Which when run gives this result

image

 

Abstract Methods

So we just talked about the F# equivalent of “virtual” members, which were ones that are abstract but also supplied a default implementation. But what about abstract members that do not supply a default implementation, how do we deal with those. Here is a small example of that, this time we have to use the AbstractClass attribute, to denote that the whole class is abstract. This allows the definition of a type with abstract members that do not have any implementation, were the actual implementation will be supplied by the inheritor of the abstract class.

[<AbstractClass>]
type SomeBaseClass() =
    abstract member SomeAbstractMethod : int -> unit
        
type SomeDerivedClass() =
    inherit SomeBaseClass()
    override this.SomeAbstractMethod(a: int) = printfn "a was %A" a |> ignore

Here is an example of a abstract class/method in use:

let foo = new SomeDerivedClass()
printfn "foo.SomeAbstractMethod(24)" |> ignore
do foo.SomeAbstractMethod(24)

Which when run gives this result

image

 

Calling Base Class Constructors

The constructor for the base class must be called in the derived class.The arguments for the base class constructor appear in the argument list in the inherit clause. This is achievable in F# though it is certainly not as pretty as it is in C# say. We have already seen the case when there is a simple no parameter constructor, but what about the cases when the base type contains a constructor that contains parameters or maybe even has several constructors, how do we deal with that. I think the best way to show how to deal with that is by way of an example. So here is an example where we have a base type that has a mixture of constructors, and is then inherited from.

type SomeBaseClass =
    val stringField : string
    new (s) = { stringField = s }
    new () = { stringField = "" }

type DerivedClass =
    inherit SomeBaseClass
    val stringField2 : string
    new (s1, s2) = { inherit SomeBaseClass(s1); stringField2 = s2 }
    new (s2) = { inherit SomeBaseClass(); stringField2 = s2 }
    new () = { inherit SomeBaseClass(); stringField2 = "" }

As you can see there is little bit more ceremony to deal with here, such as the braces “{}” and the extra use of the inherit keyword wherever you need to call a base class constructor. That said once you get used to it, I don’t think it is that bad.

Object Expressions

Sometimes you may only need to do a minor change, in which case F# offers an alternative approach to inheritance, by way of a technique called “Object Expressions”. Here is a trivial example of this:

 

let public myObjectExpressionObject = 
        { 
        new Object() with 
            override this.ToString() = "Override the object.ToString() method"
        }

It can be seen all we wanted to do was supply a new ToString() method for our usage but we did not inherit from anything at all, in fact there is no custom type at all there, just a let binding and an object expression where we override the ToString() method of the object type.

Which we can use like this:

let result = myObjectExpressionObject.ToString()
printfn "myObjectExpressionObject.ToString() = %A" result

Which will give the expected result of:

image

 

Implementing Interfaces / Calling Interface Methods

To define an interface you simply declare  a type with abstract members. To implement an interface you simply use the interface XXX with syntax, and then provide the members details for the original members of the interface. Here is a small example.

type IOrderDetails =
    abstract member Describe : unit -> string

type Order(x: int, y: string, z: DateTime) =
    interface IOrderDetails with 
        member this.Describe() = String.Format("{0} : {1} x {2}",  z.ToShortTimeString(), x, y)
  • This declares a very simple interface called IOrderDetails that has a single member
  • We then provide a custom Order type that implements the IOrderDetails interface

So that is how you declare an interface, but as some point you will want to be able to call the interface methods that you have implemented, so how do you do that?

If i create a new Order object and look at the intellisense it can be seen that the IOrderDetails.Describe member is not listed there:

image

mmmmm perhaps some sort of cast is required to cast the Order instance to the IOrderDetails interface that it implements. Yes this is the correct answer. In C# you have 2 choices here, you can use the cast operator ((IOrderDetails)o).Describe() or you may use the as keyword which can be used like this (o as IOrderDetails).Describe(). We are however not using C# and are using F, so we need to focus on what we need to do in F#.

The idea is the same though, we need to cast. Here is the working code for the example IOrderDetails interface implementation:

let o = new Order(1, "Star Wars DVD", DateTime.Now) 
printfn "((o :> IOrderDetails).Describe()) = %A" ((o :> IOrderDetails).Describe())

Which when run gives the following (expected) results:

image

Advertisements

One thought on “F#22 : Abstract classes / Overriding Methods / Implementing Interfaces

  1. “you must declare a member as abstract even you do not supply a default implementation”

    I think you mean here: “you must declare a member as abstract even you supply a default implementation”, so it’s equivalent to virtual method in C#

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: