Announcing F# 4.7

Phillip Carter

Phillip

We’re excited to announce general availability of F# 4.7 in conjunction with the .NET Core 3.0 release! In this post, I’ll show you how to get started, explain everything in F# 4.7 and give you a sneak peek at what we’re doing for the next version of F#.

F# 4.7 is another incremental release of F# with a focus on infrastructural changes to the compiler and core library and some relaxations on previously onerous syntax requirements.

F# 4.7 was developed entirely via an open RFC (requests for comments) process. The F# community has offered very detailed feedback in discussions for this version of the language. You can view all RFCs that correspond with this release here:

Get started

First, install either:

If you are a Visual Studio user, you will get an appropriate .NET Core installed by default. Once you have installed either .NET Core or Visual Studio 2019, you can use F# 4.7 with Visual Studio, Visual Studio for Mac, or Visual Studio Code with Ionide.

FSharp.Core now targets .NET Standard 2.0

Starting with FSharp.Core 4.7.0 and F# 4.7, we’re officially dropping support for .NET Standard 1.6. Now that FSharp.Core targets .NET Standard 2.0, you can enjoy a few new goodies on .NET Core:

  • Simpler dependencies, especially if using a tool like Paket
  • FromConverter and ToConverter static methods on FSharpFunc<'T, 'TResult>
  • Implicit conversions between FSharpFunc<'T, 'TResult> and Converter<'T, 'TResult>
  • The FuncConvert.ToFSharpFunc<'T> method
  • Access to the MatchFailureException type
  • The WebExtensions namespace for working with older web APIs in an F#-friendly way

Additionally, the FSharp.Core API surface area has expanded to better support parallel and sequential asynchronous computations:

  • Async.Parallel has an optional maxDegreesOfParallelism parameter so you can tune the degree of parallelism used
  • Async.Sequential to allow sequential processing of async computations

Thanks to Fraser Waters for contributing the new FSharp.Core additions.

Support for LangVersion

F# 4.7 introduces the ability to tune your effective language version with your compiler. We’re incredibly excited about this feature, because it allows us to deliver preview features alongside released features for any given compiler release.

If you’re interested in trying out preview features and giving feedback early, it’s very easy to get started. Just set the following property in your project file:

Once you save the project file, the compiler will now give you access to all preview features that shipped with that compiler.

When using F# in preview versions of .NET Core and/or Visual Studio, the language version will be set to preview by default.

The lowest-supported language version is F# 4.6. We do not plan on retrofitting language version support for F# 4.5 and lower.

Implicit yields

In the spirit of making things easier, F# 4.7 introduces implicit yields for lists, arrays, sequences, and any Computation Expression that defines the Yield, Combine, Delay, and Zero members.

A longstanding issue with learning F# has been the need to always specify the yield keyword in F# sequence expressions. Now you can delete all the yield keywords, since they’re implicit!

This makes F# sequence expressions align with list and array expressions.

But that’s not all! Prior to F# 4.7, even with lists and arrays, if you wanted to conditionally generate values it was a requirement to specify yield everywhere, even if you only had one place you did it. All the yield keywords can now be removed:

This feature was inspired by Fable programs that use F# list expressions as HTML templating DSLs.

Of course, if you prefer writing yield, you still can, with the same rules as before.

Syntax relaxations

There are two major relaxations for F# syntax added in F# 4.7. Both should make F# code easier to write, especially for beginners.

No more required double underscore

Prior to F# 4.7, if you wanted to specify member declarations and you didn’t want to name the ‘this’ identifier on F# objects, you had to use a double underscore. Now, you can only specify a single underscore, which previous language versions would reject:

This same rule has been relaxed for C-style for loops where the indexer is not meaningful:

Thanks to Gustavo Leon for contributing this feature.

Indentation relaxations for parameters passed to constructors and static methods

Another annoyance with previous F# compilers was a requirement to indent parameters to constructors or static methods. This was due to an old rule in the compiler where the first parameter determined the level of indentation required for the rest of the parameters. This is now relaxed:

Preview features

As I mentioned previously, F# 4.7 introduces the concept of an effective language version for the compiler. In the spirit of shipping previews as early as possible, we’ve included two new preview features: nameof and opening of static classes.

Nameof

The nameof function has been of the most-requested feature to add to F#. It’s very convenient when you want to log the names of things (like parameters or classes) and have the name change as you’d expect if you refactor those symbols to use different names over time. We’re still not 100% resolute on the design of it, but the core functionality is good enough that we’d love people to try it out and give us feedback. Here’s a little taste of what you can do with it:

You can also contribute to its design by proposing changes to the corresponding RFC.

Open static classes

Much like nameof, opening of static classes has been requested a lot. Not only does it allow better usage of C# APIs that assume the ability to open static classes, it can also improve F# DSLs. However, we’re also not 100% resolute on its overall design. Here’s a little taste of what it’s like:

You can also contribute to its design by proposing changes to the corresponding RFC.

F# Interactive for .NET Core Preview

Starting with F# 4.7 and .NET Core 3, you can now use F# interactive (FSI) from .NET Core! Just open a command line and type dotnet fsi to get started.

The FSI experience for .NET Core is now a very, very stable preview. There are still some quirks with dependency resolution when pulling in packages and their transitive references. We’re addressing these by adding #r “nuget:package-name” support for FSI, and we’re hoping that you’ll transition away from manually referencing third-party .dlls and instead using packages as the unit of reference for FSI.

This package management support is still only available in nightly builds of the compiler. It will become available for general usage in forthcoming support for Jupyter Notebooks via the .NET Kernel and in the first preview of .NET 5.

Updates to F# tools for Visual Studio

The Visual Studio 2019 update 16.3 release corresponds with F# 4.7 and .NET Core 3. In this release, we’ve made tooltips a bit nicer and fixed some longstanding issues in the compiler and tools that affect your experience in Visual Studio. We also spent a lot of time doing more infrastructural work to make the F# integration with Roslyn significantly more stable than it was in the past.

Record definition tooltips use a more canonical formatting:

Anonymous Records also do the same:

And record value output in FSI also uses a more canonical form:

Properties with explicit get/set modifiers will also reflect those modifiers in tooltips:

Looking back at the past year or so of F# evolution

The past year (plus a few months) has seen a lot of additions to the F# language and tools. We’ve shipped:

  • F# 4.5, F# 4.6, and now F# 4.7 with 14 new language features between the three of them
  • 6 updates to the Visual Studio tools for F#
  • Massive performance improvements to F# tooling for larger codebases
  • 2 preview features for the next version of F#
  • A revamped versioning scheme for FSharp.Core
  • A new home for F# OSS development under the .NET Foundation

It’s been quite a rush, and while the sheer number of updates and fundamental shifts to F#, we’re planning on ramping up these efforts!

Looking head towards F# 5 and .NET 5

As .NET undergoes a monumental shift towards .NET 5, F# will also feature a bit of a shift. While F# is a general-purpose language – the functional programming language for .NET – it also has a strong heritage of being used for “analytical” workloads: processing data, doing numerical work, data science and machine learning, etc. We feel that F# is positioned extremely well to continue this path, and we intend on emphasizing features that can align with these workloads more.

Some of the concrete things we’ll focus on is making F# a first-class language for Jupyter Notebooks via the .NET Kernel. We’ll also emphasize language features that make it easier to work with collections of data.

I like to think of these things as being “in addition to” everything F# is focused on so far: first-class .NET support, excellent tooling, wonderful features that make general purpose F# programming great, and now an influx of work aligned with “analytical” programming. We’re incredibly excited about the work ahead of us, and we hope you’ll also contribute in the way you see best.

Cheers, and happy hacking!

21 comments

Leave a comment