Click here to Skip to main content
15,880,972 members
Articles / All Topics

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

Rate me:
Please Sign up or sign in to vote.
5.00/5 (1 vote)
1 May 2014CPOL5 min read 13.6K   1  
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.

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


License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
United Kingdom United Kingdom
I currently hold the following qualifications (amongst others, I also studied Music Technology and Electronics, for my sins)

- MSc (Passed with distinctions), in Information Technology for E-Commerce
- BSc Hons (1st class) in Computer Science & Artificial Intelligence

Both of these at Sussex University UK.

Award(s)

I am lucky enough to have won a few awards for Zany Crazy code articles over the years

  • Microsoft C# MVP 2016
  • Codeproject MVP 2016
  • Microsoft C# MVP 2015
  • Codeproject MVP 2015
  • Microsoft C# MVP 2014
  • Codeproject MVP 2014
  • Microsoft C# MVP 2013
  • Codeproject MVP 2013
  • Microsoft C# MVP 2012
  • Codeproject MVP 2012
  • Microsoft C# MVP 2011
  • Codeproject MVP 2011
  • Microsoft C# MVP 2010
  • Codeproject MVP 2010
  • Microsoft C# MVP 2009
  • Codeproject MVP 2009
  • Microsoft C# MVP 2008
  • Codeproject MVP 2008
  • And numerous codeproject awards which you can see over at my blog

Comments and Discussions

 
-- There are no messages in this forum --