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!

Phillip Carter
Phillip Carter

Program Manager, .NET and Languages

Follow Phillip   

14 comments

  • Avatar
    Gulshanur Rahman

    Maybe for .net 5, target Python devs? Whatever they do with Python, make it simpler/easier/more intuitive to do in F#, with greater tooling support. How about Python interop?

    • Phillip Carter
      Phillip Carter

      Hey Gulshanur,

      Python interop isn’t on the immediate roadmap (such a thing would likely be a .NET runtime concept, not a language one). But we are focusing on some of the things that make Python nice for analytical work and using that as an influence for work in F#.

    • Jay Tuley
      Jay Tuley

      If you use pythonnet, the docs show how to use it with c# dynamic keyword. In f# you can use the FSharp.Interop.Dynamic library. https://github.com/fsprojects/FSharp.Interop.Dynamic
      “`
      open Python.Runtime
      open FSharp.Interop.Dynamic
      open FSharp.Interop.Dynamic.Operators

      do
      use __ = Py.GIL()
      let np = Py.Import(“math”)
      np?cos(np?pi ?*? 2) |> printfn “%O”
      let sin = np?sin
      sin 5 |> printfn “%O”
      np?cos(5) ?+? sin(5) |> printfn “%O”
      “`

  • Avatar
    Daniel Lidström

    Can you expand on this sentence? We’ll also emphasize language features that make it easier to work with collections of data.
    Where can I read language proposals, for example.
    Thanks!

    • Phillip Carter
      Phillip Carter

      Hey Eugue,

      There are no current plans for templates or designer support for WPF or WinForms. But you can certainly call the APIs in F# code. F# is already fully supported for ASP.NET Core, though we don’t surface templates with Razor files because those take a dependency on being in a C# project right now.

  • Avatar
    James Roberts

    I’m coming back to F# after being away for a few years. I took a refresher on some of the fundamentals and came across one of those nasty F#’ish issues that makes me crazy. I’m trying to chart a line and can’t seem to find any Charting tools compatible with 3.0. Am I too early to the game to try an do some plotting? Or (more likely) am I not being resourceful enough in finding a compatible library? Any advice would be so helpful. I will give you my first and second born just to show my gratitude. 🙂

  • Avatar
    Robert Boissy

    Looking ahead towards F# 5 and .NET 5

    At the Xilinx Developer Forum today MSFT announced a new family of Azure VMs that will include 1-4 Xilinx Alveo U250 FPGAs. Xilinx also announced Vitis, a comprehensive open development framework that is designed for software developers to create, port, and consume hardware-accelerated logic.

    https://www.servethehome.com/xdf19-xilinx-vitis-unified-software-platform-launched/
    https://developer.xilinx.com/

    My understanding is that most of Azure’s FPGA nodes use Intel (Altera) FPGA hardware. Azure will no doubt also support Intel’s forthcoming Agilex family of Xeon CPU/FPGA semiconductors with on-die integration. Nevertheless, Xilinx is the major FPGA hardware company.

    Lombiq’s Hastlayer effort (which even implements posits!) is interesting (and supports Xilinx FPGAs). But a more substantial effort to enable .NET 5 to consume Xilinx FPGA functionality through Vitis would be very welcome!

Leave a comment