Share via


F# Snippets 01

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.

#light

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'")

end

(* 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

end

(* 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}

end

(* Using a basic class *)

let santa = new TimelessPerson("Chris Kringle")

santa.SayHello()

(* Using a derived class *)

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

me.SayHello()

(* 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())

Console.ReadKey(false)

 

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

Comments

  • Anonymous
    December 14, 2007
    Nice post!  Very helpful.  Thanks :) One "pain point" that I've run into is how to call a method from a class constructor.  For example, in your first class, say that you wanted to call SayHello() right after setting m_name = name? This is the typical C# paradigm for WinForms -- call the InitializeComponent() method from the constructor to set everything up. I still haven't figured it out.

  • Anonymous
    January 06, 2008
    @mattman206 You can use the "then" syntax like type TimelessPerson = class    val m_name : string    new (name) as self = { m_name = name } then self.SayHello()    member public x.SayHello() = print_endline (x.m_name ^ @" says, 'Hello'") end @ChrSmith I'm not saying I have better ideas, but the duplicated "inherit" inside the definition of AgingPerson looks so ugly.

  • Anonymous
    January 06, 2008
    I think if you want to get rid of the 2nd inherit statement you can do so with ... type AgingPerson(name,age) = class ...    inherit TimelessPerson(name) as base    ... and then setting the default value attribute on m_age and giving it a value.

  • Anonymous
    January 06, 2008
    The comment has been removed

  • Anonymous
    January 13, 2009
    The comment has been removed

  • Anonymous
    January 13, 2009
    The comment has been removed