Announcing a preview of F# 4.0 and the Visual F# Tools in VS 2015

Today, we are happy to announce a pre-release of F# 4.0 and the latest Visual F# Tools, for Visual Studio 2015 Preview. F# development tools are included in the box with the VS 2015 Preview download, but these bits were branched for stabilization some time ago, and we have made significant progress since then.

We recommend that you download and install the latest Visual F# 4.0 bits here, as an update for VS 2015 Preview.  This blog reviews the key enhancements and changes completed up through this update package.  VS 2015 Preview ships with F# components matching commit 3a27cd8 (from October 12).  The update brings the F# bits up to date with commit afe5027 (from November 11).

Overview

More to come

Today’s release is just an early preview of F# 4.0 and the latest Visual F# Tools. There is still a lot more language and tooling work planned, but we think now is a good time to step back and talk about what’s been completed so far.  There’s quite a lot! In-progress features and up-to-date status can be found on our Codeplex page.

By and for the F# community

Since enabling community contributions to the compiler in April, then opening up the F# Visual Studio stack in June, the F# language and Visual F# IDE tooling stack has been developed in full partnership with the open source developer community. In just this short time, the Visual F# project has received a stunning 159 pull requests from 32 developers, of which we have so far been able to apply 90.

More so than any previous release, Visual F# 4.0 represents the hard work, dedication, and contagious enthusiasm of the F# open source community.  Much of the new content described below was developed largely or completely by non-Microsoft contributors. The community, in partnership with Microsoft Open Technologies, the F# Software Foundation, and others, have developed F# into a mature, cross-platform, functional-first language.

Further links

There is lots of other news relevant to Visual Studio F# developers, today.  Check out some of these links:

  • Soma’s blog
    • Highlights of today’s VS 2015 news, including the free Visual Studio Community Edition, which supports F# and extensions like the Visual F# Power Tools
  • C#/VB team blog
    • Links to content covering new developments in those “other” .NET languages
  • Visual Studio Connect
    • Live stream/recording of presentations covering VS 2015 announcements
    • Visual F# will be represented at the Day 2 Managed Languages panel – tune in!

Enough talk, let’s look at what’s new for F#!

New Language Capabilities

Constructors as first-class functions

As a functional-first language, F# has always provided rich support for processing and manipulating function values, both curried-style functions and traditional .NET methods.  One longstanding gap in that support was for constructors – there was no way to treat a type constructor as an isolated function that could be passed around and composed with other functions.  This limitation was one of the few sources of boilerplate in F# code, mandating the use of small lambda functions in order to invoke constructors.

This is now resolved – constructors are now treated as first-class functions, with the same treatment as other traditional .NET methods.

So, as an example, instead of writing this:

ctor1

You can now write this:

ctor2

Simplified use of mutable values

Mutable values are permitted in F#, though immutability is the default.  In the past, the ‘mutable’ keyword was used to designate a stack-based mutable value, and that value could be mutated using the <- operator.  If the mutable value happened to be captured by a closure and a heap-based value was required, the ‘ref’ syntax was needed instead, and mutation was done via the := operator.

These distinct syntaxes led to some code inelegance and developer confusion, as it was often difficult to reason ahead of time about which approach was going to be required.

With F# 4.0, developers can now just use the ‘mutable’ keyword for all mutable values, and the compiler will take care of the rest, creating a stack-based value if possible, otherwise implicitly converting to a ref cell.

So whereas you previously needed a ‘ref’ value for ‘total’ here:

mutref1

You can now use ‘mutable’ and it “just works”:

mutref2

Advanced users who prefer to have explicit knowledge of the stack/heap semantics can enable warning 3180 (–warnon:3180 for fsc.exe or fsi.exe) and will be notified when a ‘mutable’ declaration has been implicitly converted to ‘ref’.

Support for high-dimensional arrays

The .NET framework supports up to 32-dimensional arrays, but in the past F# only supported use of up to rank-4 arrays.  Not only were arrays of rank 5+ not possible to create and manipulate from F# code, the compiler could sometimes fail to consume external libraries which relied on high-dimensional arrays.

This is now fixed.  Although there is not yet support for creating and manipulating high-rank arrays, the compiler will now properly handle these types up to rank-32.

Support for static parameters to provided methods

F# type providers were previously limited to accepting static parameters only on the top-level provided type. From there, all other provided types, methods, and properties needed to be generated based on this single set of parameters.

With F# 4.0, the type provider mechanism has been expanded to allow for static parameters on provided methods, as well.

With this change, instead of requiring users to declare multiple top-level types, each with distinct parameters, there is now an option to use a single type declaration along with parameterized usage of methods.  For certain kinds of type providers, this can greatly streamline the developer experience.

A simple example is a provided “safe string” type which enforces that the number of slots in a String.Format format string matches the number of arguments passed.  This can now be done with a single type declaration, and a parameterized Format method:

staticmeth

Slicing syntax support for F# lists

F# linked lists now support the familiar “slicing” syntax, long present for arrays, for reading elements and creating sub-lists.

listslice

Simplified usage of units of measure with printf-family functions

printf-family functions previously required developers to explicitly strip off any measure information before values could be formatted.

This requirement has been relaxed – values with measure information are now handled seamlessly.

printfuom

Modified GC settings on the compiler for better performance

Not a language feature, but surely of interest to F# language developers, is a change to the GC mode used by the F# compiler.  fsc.exe now uses GCLatencyMode.Batch, which gives a noticeable improvement in overall throughput, something that any F# developer will welcome.

Our testing indicates that this setting alone can provide upwards of 10% better compile performance. Click the chart below for a full-size plot of the performance data.

fsc.exe performance data, click for full size

 

Enhancements to the FSharp.Core runtime

Normalized collections modules

The three collection types used most frequently in F# code are Array, List, and Seq.  Each of these types has a dedicated module containing various higher-order processing functions.  These functions are probably familiar to any functional programmer or LINQ user – map, fold, iter, etc.

In the past, these functions were not all uniformly available across the collection types. For example, the ‘distinct’ function was present for Seq, but missing for Array and List. The ‘tail’ function was present for List, but not for Array or Seq.

To work around these gaps in the API, developers would often need to convert their collections from one type to another, and back, just to take advantage of a particular function. This often led to inelegant and inefficient code.

In F# 4.0, the collections API has been fully normalized across Array, List, and Seq.  There are now dedicated, optimized implementations of all common operations for each type, and even a few brand-new functions.  This represents the addition of a whopping 95 APIs in total.

The chart below shows the new APIs (green), previously-existing APIs (blue), and intentional remaining gaps (white). Click for full size.

collections API additions - click for full size

Faster generic comparison

The internal tables of optimized hash-comparison implementations used by F# code have been expanded and improved, leading to significant performance gains when processing primitive types such as int, string, and so on.

Performance improvements of 5x or more can be found in F# 4.0 when using APIs such as {List/Array/Seq}.{distinct/distinctBy/groupBy} which rely heavily on these comparisons.

Better async stack traces

Exceptions occurring in F# async code now have their stack traces preserved in a more user-friendly way, namely the top frame should now always point to the proper origin of the exception.

For code like this:

asyncstack

The top frames of the stack trace were previously rather opaque:

System.Exception: Boom
   at <StartupCode$FSharp-Core>.$Control.StartImmediate@1471-1.Invoke(Exception exn)
    at Microsoft.FSharp.Control.CancellationTokenOps.StartWithContinuations@1230-1.Invoke(Exception x)

But now point directly to the relevant code:

System.Exception: Boom
   at FSI_0011.f1@1-3.Invoke(Unit unitVar) in Script.fsx:line 1
   at Microsoft.FSharp.Control.AsyncBuilderImpl.callA@849.Invoke(AsyncParams`1 args)
   — End of stack trace from previous location where exception was thrown —

Assorted small performance improvements

A variety of small performance optimizations have been made across the runtime and compiler, making progress toward longer-term goals of faster compile time and a highly-optimized FSharp.Core runtime.

VS tooling improvements

Assembly metadata in project templates

All of the in-box F# project templates have been updated to now include an AssemblyInfo.fs file, containing default values for various assembly-level attributes like AssemblyVersion, AssemblyTitle, etc.  This aligns F# project templates better with those of other languages (e.g. C#), where such files have long been used.

assemblyinfo

Improved startup time for FSI

In F# 3.1.2, support was added for using non-locking shadow copy when referencing DLLs in F# Interactive.  One downside of enabling this feature was that it caused fsi.exe to be noticeably slower on startup.

This issue is now largely resolved, after adjusting the AppDomain loading behavior for the process.

New hotkeys for FSI

From within Visual Studio, hotkeys are now assigned for the “Reset” and “Clear All” actions of F# Interactive.  “Reset” is now mapped to Ctrl+Alt+R, and “Clear All” is now mapped to “Ctrl+Alt+C”.  These mappings were chosen to match those found in other F# IDEs.

hotkeys

Feedback

We are excited for users to start dogfooding Visual F# 4.0 and VS 2015.  Please log any issues on our Codeplex page: https://visualfsharp.codeplex.com/WorkItem/Create

Enjoy!