Announcing F# 5 preview 1

Phillip Carter

We’re excited to announce that F# 5 preview 1 is now available! Here’s how to get it:

If you’re using Visual Studio on Windows, you’ll need both the .NET 5 preview SDK and Visual Studio Preview installed.

Using F# 5 preview

You can use F# 5 preview via the .NET 5 preview SDK, or through the .NET and Jupyter Notebooks support.

If you’re using the .NET 5 preview SDK, check out a sample repository showing off some of what you can do with F# 5. You can play with each of the features there instead of starting from scratch.

If you’d rather use F# 5 in your own project, you’ll need to add a LangVersion property and add a package reference to the latest FSharp.Core in your project file. It should look something like this:

In future previews, the FSharp.Core reference shouldn’t be required.

Alternatively, if you’re using Jupyter Notebooks and want a more interactive experience, check out a sample notebook that shows the same features, but has a more interactive output.

F# 5 is focused on better interactive and analytical programming

It’s difficult to come up with a “theme” for a programming language release. Whenever we start a new “cycle” and think about what we’d like to do for the next version of F#, what we have in mind is often very different from what we end up shipping. This is caused by numerous factors: designs don’t work out the way we think they would, things are too difficult to implement at an acceptable level of quality, existing customers report problems that are very expensive and time consuming to fix, etc.

This time, things are different. We started with the intention of improving interactive programming with F#, aligning with the recent investments made to support .NET in Jupyter Notebooks. Interactive programming has historically been a strength of F#, but improving that aspect of F# has been neglected for a few years. With interactive programming becoming increasingly important as machine learning and data science rise in popularity, it was clear that improvements had to be made in the overall experience. Many of these improvements are language changes, and we plan on introducing more features in future preview that are aligned with this.

Not every feature that ultimately ships with F# 5 is targeted specifically to make interactive programming better. F# is a general purpose language after all, and language additions or enhancements have broad use cases that go far beyond a particular style of programming. However, our intention is that the full set of F# 5 features combined makes interactive programming better than it is today. Let’s dive in!

Package references for F# scripts

One of the biggest problems with F# scripts today is incorporating packages. This is now easy to do with the new #r "nuget:..." command:

This will download and install the latest JSON.NET package (if it’s not in your package cache), resolve all dependencies, and let you use the library as if it were in a fully-fledged project.

To run this script (assuming you name it script.fsx) in F# interactive, simply type:

dotnet fsi --langversion:preview script.fsx

Note that the --langversion flag is required. This will not be required once F# 5 is released.

Alternatively, if you’re using Jupyter notebooks, simply execute the cell and it will print the result.

In future previews, we will work to make sure the editor experience in IDEs is in good shape. The focus on this first preview has been in hardening the core mechanism and integrating it with Jupyter Notebooks.

Enhanced slicing

Slicing data is critical when doing analytical work on sets of data. To that end, we enhanced F# slicing in three areas.

Consistent behavior for built-in data types

Today, behavior for slicing the built-in FSharp.Core data types (array, list, string, 2D array, 3D array, 4D array) is not consistent. Some edge-case behavior will throw an exception and some won’t. In F# 5 preview, all built-in types now return empty slices for slices that are impossible to generate:

This change could be controversial to some – the variety of opinions on slicing behavior we’ve seen in other languages has shown that slicing behavior is a hotly debated topic – so we want people to try it out early and let us know how they feel about this change in their own code.

Fixed-index slices for 3D and 4D arrays in FSharp.Core

The built-in 3D and 4D array types have always supported slices, but they did not support fixing a particular index (such as the y-dimension in a 3D array). Now they do!

To illustrate this, consider the following 3D array:

z = 0

x\y 0 1
0 0 1
1 2 3

z = 1

x\y 0 1
0 4 5
1 6 7

What if we wanted to extract the slice [| 4; 5 |] from the array? This is now very simple!

This kind of slice used to not be possible prior to F# 5.

Reverse indexes and slicing from the end

Finally, we have added the concept of a reverse, or “from the end” index. The syntax is ^idx. Here’s how you can an element 1 value from the end of a list:

You can also define reverse indexes for your own types. To do so, you’ll need to implement the following method:

GetReverseIndex: dimension: int -> offset: int

Here’s an example for the Span<'T> type:

We feel that these three enhancements will make slicing data types more convenient in F# 5. What do you think?

The nameof function

The nameof function is a new addition to F#. It’s very useful doing things like logging or validating parameters to functions. Because it uses actual F# symbols instead of string literals, it makes refactoring names over time less difficult.

Consider the following example:

The last line will throw an exception, and the name of the parameter month will be shown in the message.

You can take a name of almost everything in F#, such as:

  • Parameters
  • Functions
  • Classes
  • Modules
  • Namespaces

There are some current restrictions on overloaded methods and type parameters that we are planning on addressing in future previews.

Opening static classes

We’re introducing the ability to “open” a static class as if it were a module or namespace. This applies to any static class in .NET (or any package), or your own F#-defined static class.

There are currently a few unresolved design questions related to shadowing vs. building an overloaded set of methods when combining members from static classes that have the same name. Today, they shadow. That may change in the future. We’re also evaluating if we wish to support opening generic static classes with specific generic substitutions. This kind of change would make the feature very expressive, but it would also be fairly advanced and/or niche.

Applicative computation expressions

Computation expressions (CEs) are used today to model “contextual computations”, or in more FP-friendly terminology, monadic computations. However, they are a more flexible construct than just offering syntax for monads.

F# 5 introduces applicative CEs, which are a slightly different form of CE than what you’re perhaps used to. Applicative CEs allow for significantly more efficient computations provided that every computation is independent, and their results are merely accumulated at the end. When computations are independent of one another, they are also trivially parallelizable. This benefit comes at a restriction, though: computations that depend on previously-computed values are not allowed.

The follow example shows a basic applicative CE for the Result type.

We’re excited to see the clever ways F# programmers will utilize this feature, especially in their own libraries.

If you’re a library author who exposes CEs in their library today, there are some additional considerations you’ll need to be aware of. We recommend that all interested library authors read the summary of new builder methods to determine which to use. We will document these members in the official documentation for CEs once F# 5 is closer to release and the overall design is no longer subject to change.

For consumers of applicative CEs, things aren’t too different from the CEs that you already use. The previously-mentioned restriction around independent computations is the key concept to understand.

The road ahead for F# 5

Despite a number of features being available today, we’re still very much in active development for F# 5. When new features are ready, we’ll release them in the next available .NET 5 preview. If you’re curious about what could be coming next, check out the following links:

Finally, we track all language suggestions in our language suggestions repository. There are quite a lot of suggestions you can learn about, and we encourage you to participate in each discussion.

Because previews are released so that we can get feedback from users, we might make breaking changes from one preview to the next to accommodate feedback we feel deserves a design change. We might also decide to keep a feature in preview for the F# 5 GA release if there is enough feedback that the design isn’t quite right. We encourage you to try these features out and let us know what you feel needs improvement!

Special addendum (2020-03-18): we’re hiring!

Want to help shape F# 5 and future releases? We’re expanding our team in Prague, Czech Republic! If the idea of working on new language and compiler features and improving the overall F# developer experiences sounds interesting, give the job posting a look.

Cheers, and happy hacking!