Introducing F# 4.0
While all of the recent news has been focused on C# and Windows 10, F# isn’t standing still. Along with Visual Studio 2015 RC is the latest version of F# 4.0.
The first thing that should be noted is that it is truly a community project. Of the 38 contributors, only a quarter of them have any affiliation with Microsoft. All work was done in the open on the F# GitHub site, which is also where they would like feedback to be directed.
This release brings numerous changes to both the language and the runtime as well as a few IDE enhancements. You can see the full list on the F# blog, so we’re just going to hit the highlights.
Metaprogamming in .NET via expression trees has been a very important feature since the introduction of LINQ in .NET 4.0. With F# 4.0, working with expression trees is becoming easier than ever.
If you tag an argument of type FSharp.Quotations.Expr with the ReflectedDefinition attribute, the call site automatically switches to call-by-name semantics. Previously you would have to annotate the call site as shown in expressions 1 and 2 below. As shown in expression 3
Test.Expression1 ( <@ x + 1 @> ) //typed expression
Test.Expression2 ( <@@ x + 1 @@> ) //untyped expression
Test.Expression3 ( x + 1 ) //typed expression with ReflectedDefinition attribute
By eliminating the burden of explicitly quoting expressions, libraries that use metaprogramming techniques become much easier to work with.
Improved Preprocessor Directives
Believe it or not, until now F# had very limited support for preprocessor directives. Boolean operations such as “#if TRACE || DEBUG” were not possible until this version. The work-around for F# 3 and earlier is to use nested #if statements to simulate “and” expressions and duplicated code for “or” expressions.
Units of Measure
When working on scientific or engineering applications, errors often occur due to mistakes in units. For example, you may have one measurement in inches and another in meters. Back in 1999 this mistake caused the loss of the Mars Orbiter, a 125 million dollar space probe.
F# eliminates this class of bug through a concept known as units of measure. Scalar values become unit measurements by appending values with suffixes such as “<cm>” or “<miles/hour>”. As the next line shows, even conversions between units are expressed in terms of units of measure.
let cmPerInch : float<cm/inch> = 2.54<cm/inch>
The new feature for F# 4 is the ability to use fractional exponents in a unit of measure expression. For example:
[<Measure>] type Jones = cm Hz^(1/2) / W
Inheritance from types with multiple generic interface instantiations
This is a tricky one to understand if you aren’t familiar with F# and a frustrating one if you are. To begin with, let us consider a class that represents hexadecimal numbers. In C#, you may wish to design this class to be comparable to both strings and integers.
public class Hexidecimal : IComparable<string>, IComparable<int>
Due to the complex nature of F#’s type inference, it was previously unable to express this class. Not only can you not define a type with multiple interfaces that only differ by the type argument, you can’t inherit from one that does so either.
F# 4 doesn’t completely solve this problem but it does provide a workaround. You can now create two classes, one for each interface, and then have the second class inherit from the first. The code is a little tedious, but it is occasionally necessary when working with C# based libraries.
Extension properties in Object Initializers
Extension properties, a feature much desired in C#, are already available in F#. With this release, extension properties can now be used in object initializers.
Removing the Microsoft Brand
Following a tradition that dates back to Visual Basic 7, the language specific namespaces for F# all start with “Microsoft.FSharp”. But with F# being more community driven than Microsoft owned, this no longer seems appropriate and the Microsoft brand is being phased out.
>In this vein, to keep F# code itself vendor- and platform-neutral, the leading “Microsoft.” can now be optionally omitted when referring to namespaces, modules, and types from the FSharp.Core runtime.
Performance Improvement: Non-structural Comparisons
By default, F# uses structural comparisons instead of the types built-in operators such as op_Equality. While this makes performing complex data comparisons easy, performance can suffer.
When you desire the performance or semantics of the built-in comparison operators, you can now use “open NonStructuralComparison’ to change the way operators such as = work. In one simple benchmark comparing DateTime objects in a loop, the performance improvement was over an order of magnitude.
Prior to VS 2015, F# developers had to choose between using F#’s interactive mode and having full access to the debugger. With this feature, you can now right-click on an F# script and run it under the debugger, thus getting the best of both worlds.
In VS 2013 and earlier, there was no way for Visual Studio to detect when an F# project needed to be built. So instead, F# projects were always rebuilt even when nothing changed. By adding “up-to-date” support in VS 2015, developers no longer have to wait for projects to be needlessly built.
Other features include improved Intellisense, interopt APIs for Option<T>, async workflow extensions for WebClient, and more.