This week I had the pleasure of writing some of our test automation infrastructure in F#. Not only does this give us a chance to dogfood the language, but it also helps us find pain points in the developer experience. For me at least, the biggest pain point right now is a lack of F# examples surrounding core syntax.

But I would like to help combat this, so I've written a very simple app to show how to do basic object inheritance as well as implement an interface. If you have any suggestions or comments about language constructs that seem difficult to use or could use more examples please let me know.



open System


(* Define a simple class with private field *)

type TimelessPerson = class

    val m_name : string


    // This syntax is to specify a public constructor which takes an

    // argument. It then uses the Record Initialization syntax.

    public new (name) = { m_name = name }


    // Define a public member function 'SayHello'. F# doesn't use a

    // 'this' keyword, rather you specify the 'this' variable yourself.

    // In this case 'x' is refering to the this pointer.

    member public x.SayHello() =

        Console.WriteLine(x.m_name ^ @" says, 'Hello'")



(* Defines a simple interface *)

type IAge = interface

    // in C# void GrowOlder(TimeSpan elapsedTime)

    abstract GrowOlder : TimeSpan -> unit

    // A property. In C# int Age { get; }

    abstract Age : int



(* Define a derived class which also implements an interface *)

type AgingPerson = class

    // Inherit from TimelessPerson and define the 'baseclass' as

    // 'base'

    inherit TimelessPerson as base


    interface IAge with

        // Implement the GrowOlder method.

        member public x.GrowOlder elapsed =

            x.m_age <- x.m_age.Add(elapsed)

            Console.WriteLine(base.m_name ^ " has aged " ^ elapsed.ToString())

        // Implement the Age property, notice the 'getter' syntax. If

        // the property weren't read only we would write:

        // ... with get() = ... and set(x) = ...

        member public x.Age with get() = int_of_float (x.m_age.TotalDays / 365.0)


    val mutable m_age : TimeSpan


    // In order to call the base class's constructor you need the

    // 'inherit BaseClassName()' structure.

    public new(name, age) = { inherit TimelessPerson(name); m_age = age}




(* Using a basic class *)

let santa = new TimelessPerson("Chris Kringle")



(* Using a derived class *)

let me = new AgingPerson("Chris Smith", (new TimeSpan(365 * 25,0,0,0)))



(* Casting me to the IAge interface, and calling methods/properties *)

let myIAgeInterface = me :> IAge

myIAgeInterface.GrowOlder(new TimeSpan(12,0,0))

Console.WriteLine("My age = " + myIAgeInterface.Age.ToString())




Note: this code snippet is "AS IS" and provides no warranties or rights, expressed or implied.