A Taste of What’s New in F# 1.1

The first "technology preview" relese of F# 1.1 will be released in the next few days.  This is an exciting time for the project, and we're sure you'll enjoy the additions we've made to the language, the libraries and the interactive development environment. 

One of the really great new additions is "F# Interactive", a top-level interactive environment for F#, which lets you use F# as a type-safe, scalable interactive scripting language.  This is really revolutionizing the way I work with F# - I've used top level environments before, but never one that has such a rich set of foundation libraries, combined with type-safety, type inference, dynamic linking, support for reflective operations and efficient execution. However, I'm going to save a detailed blog entry on this until later, and am also looking forward to having the interactive environment embedded in Visual Studio.

The major addition to the F# language itself in this release is what we're calling the "F# Object and Encapsulation Extensions".  This combines what I've found to be the best features of the .NET object oriented paradigm with the functional programming model that lies at the core of F#.  This means that F# has become a mixed functional/imperative/object-oriented programming language.  If you're an object-oriented programmer, you will find the class description language succinct.  For example, here's a signature for a control from one of the F# Interactive DirectX scripts we've been working on:

type Canvas3DControl =
    inherit Control
: unit
-> Canvas3DControl
Device : Device
    member Scene  : List<SceneItem> with get,set
    member Render : unit -> unit

For orientation, "new" declares a constructor, "Device" is a readonly property, Scene is a get/set property and Render is a method.  The implementation of the class is essentially as follows:

type Canvas3DControl
val device: Device;
    val mutable items : List<SceneItem>;
inherit Control();
        device =
new Device(...);
        items = [] }
member x.Device = x.device
member x.Scene 
with get() = x.items
      with set(v) =
        x.items <- v;
    member x.Render() = 
      List.foreach x.itemsD (fun f -> f.Render());

You can see from this that implementations of classes have essentially all their types inferred.  Signatures are optional, so this means you can rapidly prototype classes without having to write all those pesky types (The types are statically checked, of course, but type inference just means the compiler works out the types most of the time).  Classes can also include static members, interface implementations, virtual method slot declarations and override declarations.

But we've not only added OO classes to F# - we've brought the goodness of functional programming and the OO paradigm together.  One way in which we've done this by allowing type augmentations.  For example, you can augment any F# type definition with members, regardless of whether the F# type is implemented as a class, record or discriminated union.  In practical terms this means the F# programmer can "dress up" F# types in .NET clothes, and furthermore can make use of types as a basic organising structure within his/her code.  For example, here's the (partial) signature of one of the new types we've added to the F# library:

type BigNumber  

    static member (+): num * num -> num
    static member (*): num * num -> num
    static member (-): num * num -> num
    static member (/): num * num -> num
    interface IComparable
Details : Math.Rational

Note the signature shows that this is an abstract type (not abstract in the C# sense, but rather a "good ol' ADT").  The abstract type comes equipped with static member operators.  Underneath a BigNumber could be anything; class, record or discriminated union.  In this case it is the latter:

type BigNumber =
  // | I of nativeint 
Z of Math.BigInt
Q of Math.Rational

This discriminated union says that a BigNumber is implemented as either a Rational or a BigInt, with a comment indicating that we plan to add small machine-sized integers as a representation in the future.  Discriminated unions give internal safety to your code (the compiler tells you if you haven't covered all the cases), and augmentations give you the value of the "dot" notation in external presentation.  

[ Aside: The signature also above mentioned two interfaces - these are for F# comparison and hashing, which we override because the default F# comparison and hashing functions don't guarantee the natural term order we need for this type.  I'll also mention that the F# module containing BigNumber comes with extra F# values for performing additional algorithmic operations on BigNumbers.  Finally a member property Details is shown in the signature.  It is becoming standard in F# code to use a property named "Details" for the "projection idiom", i.e. to represent a member which projects out the logical contents of a type, regardless of representation.  It turns out that BigNumbers are really rationals, and that the Z alternative is only an optimization, hence the Details property returns a rational.   ]

A little more of the implementation is shown below: note how augmentations of F# types can appear after the main definition, though they are currently required to appear in the same file as the original type. 

type BigNumber
member x.Details =
match x with
Z z -> Math.Rational.of_z z
Q q -> q

System.IComparable with 
  member x.CompareTo(y:obj) = compare x (y :?> BigNumber)

It is very common for types to be defined at the beginning of a file, operator augmentations in the middle and final "member" augmentations to be given at the end. Augmentations mean we achieve the conceptual clarity of an interface organised around the dot-notation, while nearly always maintaining the definition-before-use property that is so characteristic of F#/ML programming.  This is essential, as it is the basis for using F# as a scripting language, and is the property that ensures that F# code is essentially free from the null-pointer problems. 

We're really happy with how the object and encapsulation extensions have turned out - it makes it OO programming very pleasant indeed, and puts added code structuring and dot-notation mehanisms at the disposal of existing F# programmers.   We've worked hard to ensure that members, classes and augmentations interact well with other aspects of F#, e.g. generics, type inference and scripting.  We look forward to your feedback, and feel confident you'll enjoy using the new release when it comes out.


Comments (10)

  1. Lars Nilsson says:

    Looks wonderful! Can’t wait to get my hands on it. 🙂 I believe lots of kudos are in order for your (plural, of course, since I believe multiple people are working on F#) accomplishments. I have more or less stopped my C++ developments in VS.NET and all my new projects are now being developed in F# (I have no external influences that would force me to go one way or another).

  2. Lars Nilsson says:

    Looks wonderful! Can’t wait to get my hands on it. 🙂 I would like to thank all people involved in the work on F#. I have switched all my new delevopments to F# from VC++, and have no intention of going back at this point, and find it so much more pleasing to write programs.

  3. I’m pleased to announce that the first candidate release of F# 1.1 is now available from the Microsoft…

  4. I’m pleased to announce that the first candidate release of F# 1.1 is now available from the Microsoft…

  5. Dr. Syme,

    Congratulations to you and your team on release Thanks for all of the efforts, it is truly appreciated.

    I’ve downloaded it and hope to have some time this weekend to give it a look. If your previous releases are any indication, this should be fun. Time to become proficient with the new features should be my only impediment, so I’m hoping to devote a bit more time to F# in the coming months.



  6. I’m pleased to announce that the first candidate release of F# 1.1 is now available from the Microsoft…

  7. Dr. Don Syme and his good group at Microsoft Research have released F#;nbsp;(with pre-release…

  8. In the last entry we created a service container that could construct a hierarchy of singleton services

Skip to main content