A Peek into F# 4.1
Later this year, we’re going to ship a new version of Microsoft’s tools for F#. This will include support for F# 4.1, featuring important incremental improvements to the language that have been developed in conjunction with F# users and contributors. Our tools will also include a cross-platform, open-source F# 4.1 compiler toolchain for .NET Framework and .NET Core, suitable for use on Linux, macOS/OS X, and Windows. We are also updating the Visual F# IDE Tools for use with the next version of Visual Studio.
The Visual F# Tools for F# 4.1 will be updated to include support for editing and compiling .NET Core and .NET Framework projects. The Visual F# Tools will also include incremental fixes and integration with the new Visual Studio installation process. Additionally, we are currently working towards support for Roslyn Workspaces in the Visual F# Tools. By using Roslyn Workspaces, the Visual F# Tools will “plug in” to tooling innovations made in Visual Studio and be able to offer a more modern editing experience.
In this blog post, we explore what we plan to ship in more detail. For followers of our primary GitHub repository these specifics will already be familiar, however we thought it useful to bring them together into a single post. This post doesn’t cover the many generic improvements to Visual Studio, .NET and Xamarin which F# aso benefits from.
Finally, we are partnering with the F# community, including other groups at Microsoft, to ensure that F# 4.1 support is rolled out across the wide range of tooling available for F# 4.1. This includes support in Visual Studio Code, Xamarin Studio, and the popular Visual F# Power Tools for Visual Studio.
Support for the .NET Standard and .NET Core
Our compiler and scripting tools for F# 4.1 will be the first version to offer support for .NET Core. This is in addition to the existing support for .NET Framework 4.x development. When you write F# code on .NET Core today, you’re using a pre-release of F# 4.1 and this compiler toolchain.
Our tools for F# will continue to fully support .NET Framework development in a backwards-compatible way. This includes compiling existing projects created with earlier versions of Visual Studio and running existing scripts using F# Interactive (fsi.exe). Support for the latest versions of the .NET Framework is being added to these tools.
The Microsoft compiler tools for F# 4.1 are compatible with the .NET Standard, and thus are fully compatible with .NET Core and .NET Framework. The FSharp.Core library supports the .NET Standard, which allows you to use it for both .NET Core and .NET Framework development.
On Linux and macOS/OS X, the F# compiler runs as a .NET Core component, as .NET Framework is not supported on those platforms. You can also run the F# compiler as a .NET Core component on Windows.
Currently, this support is in alpha. Our aim is that the RTM support for .NET Core will coincide with the official release of F# 4.1.
Note: Until the release of .NET Standard 2.0, Type Providers will not be available on .NET Standard or .NET Core.
Getting Started with F# 4.1 on .NET Core
Note: At the time of writing, .NET Core 1.0 SDK tooling is still in preview. Details here are likely to change as that tooling evolves.
To get started on .NET Core, install the .NET Core 1.0 SDK Preview 2 tooling.
Next, create a directory somewhere on your machine, open a command line, and type:
dotnet new -l f#
This will drop three files in your directory: a
project.json file, an F# source file, and a
- Delete the
- Change the
project.jsonfile to the following:
Now you can restore packages, build the project, and run it to see output with the following commands:
$ dotnet restore
$ dotnet build
$ dotnet run
To learn more about getting started with F# on .NET Core, read Getting Started with F# on .NET Core.
New Language Capabilities in F# 4.1
The F# 4.1 programming language introduces a number of new language capabilities focused on programmer flexibility and incremental improvements in focused areas of the language. The F# language was been developed collaboratively with F# users and the community, including many contributions from Microsoft.
Struct Tuples and Interop with C# 7/VB 15 Tuples
The tuple type in F# is a key way to bundle values together in a number of ways at the language level. The benefits this brings, such as grouping values together as an ad-hoc convenience, or bundling information with the result of an operation, are also surfacing in the form of struct tuples in C# and Visual Basic. These are all backed by the ValueTuple type.
To support the
ValueTuple type and thus support interop with C# and Visual Basic, tuple types, tuple expressions, and tuple patterns can now be annotated with the
Here’s how looks:
Note that struct tuples are not capable of being implicitly represented as reference tuples:
Additionally, struct tuples allow for performance gains when in a situation where many tuples are allocated in a short period of time.
Status: In Progress
In F# 4.1, a record type can be represented as a struct with the
[<Struct>] attribute. This allows records to now share the same performance characteristics as structs, without any other required changes to the type definition. Here’s an example:
There are some key behavioral things to note for struct records:
- To use mutable fields within the record, any instance of the record must also be marked as mutable.
- Cyclic references cannot be defined in a struct record.
- You cannot call the default constructor for struct records, like you can with normal F# structs.
- When marked with the
CLIMutableAttribute, a struct record will not create a default constructor, because structs implicitly have one (though as stated above, you can’t call it from F#).
Author: Will Smith
Struct Unions (Single Case)
In the spirit of more support for structs, in F# 4.1 the single case of the Union type will also be capable of being represented as a struct with the
[<Struct>] keyword. Single case Union types are often used to wrap a primitive type for domain modelling. This allows you to continue to do so, but without the overhead of allocating a new type on the heap. Here’s an example:
Similar to struct records, single case struct unions have a few behavioral things to note:
- You cannot have cyclic references to the same type be defined.
- You cannot call the default constructor, like you can with normal F# structs.
In .NET Intermediate Language (IL), it is possible to “pin” a pointer-typed local on the stack. C# has support for this with the
fixed statement, preventing garbage collection within the scope of that statement. This is useful for native interop scenarios. This support is coming to F# 4.1 in the form of the
fixed keyword used in conjunction with a
use binding. Here’s an example:
There are some behavioral characteristics to note here:
- The usage of
fixedcorresponds with a
useto scope the pointer, e.g.
use ptr = fixed expr.
- Like all pointer code, this is an unsafe feature. A warning will occur when you use this.
Underscores in Numeric Literals
We’re also bringing support for placing underscores in numeric literals with F# 4.1. This enables you to group digits into logical units to make numeric literals easier to read. Here’s an example:
Author: Avi Avni
Caller Info Argument Attributes
This allows for the ability to mark arguments to functions with the Caller Info attributes
CallerMemberName. These attributes allow you to obtain information about the caller to a method, which is helpful for tracing, debugging, and creating diagnostic tools. Here’s an example:
Adding a Result Type
Similar to the Rust language Result enum type, we are adding support for a
Result<'TSuccess, 'TError> type. A sibling of the
Result<'TSuccess, 'TError> is being added to support the use case of wanting to consume code which could generate an error without having to do exception handling.
Only the type and three functions are being added at this time –
bind. These three functions will aid in composing functions which return Results. Other functionality, extending APIs in FSharp.Core, and more are under discussion in the Result type RFC Discussion.
Here’s an example:
You might ask, “why do this when you already have
Option<'T>?”. This is a good question. When you consider the execution semantics of your code, Result and Option fill a similar goal when accounting for anything other than the “happy path” when code executes. Result is the best type to use when you want to represent and preserve an error that can occur during execution. Option is better for when you wish to represent the existence or absence a value, or when you want consumers to still account for an error, but you do not care about preserving that error.
Author: Oskar Gewalli
Mutually Referential Types and Modules Within the Same File
This addition to the language allows for a collection of types and modules within a single scope in a single file to be mutually referential. The way this is specified is with the
rec keyword in a top level namespace or module, e.g.
module rec X,
namespace rec Y.
Similar to the opt-in nature of the
and keyword used to allow functions and types to be mutually referential, this allows you to opt-in to doing so over larger scopes.
This solves a common problem in a number of scenarios, such as needing to construct extra types to hold static methods and static values, organizing helper functions into modules, raising an exception in members of a type and expecting the exception to carry data of that same type, and so on.
Here’s an example:
Implicit “Module” Suffix on modules which share the same name as a type
With this feature, if a module shares the same name as a type within the same declaration group (that is, they are within the same namespace, or in the same group of declarations making up a module), it will have the suffix “Module” appended to it at compile-time.
This pattern, giving a module which is related to a type the same name as that type, is a common pattern which was traditionally supported by the
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix )>] attribute, as such:
With F# 4.1, this is now implicit, so you can omit the attribute:
C# 7 is adding support for byref locals and byref returns to support better high performance scenarios. This will result in libraries which use these features. F# already has support for ref locals with ref cells, but to date has had no support for consuming or generating byref-returning methods. This support is coming in F# 4.1.
Note At the minimum, F# 4.1 will support consuming byref-returning methods. At the time of writing, ref returns are not complete for C# and the work in F# is still in very early stages.
Status: In Progress
Error Message Improvements
Lastly, there has been an incredible community-driven effort to improve error messages across the language. There are a few themes in these improvements, most notably in adding or improving suggested fixes with information the compiler already has.
Here’s a sample of one of the improvements. When compiling the following code,
Output with F# 4.0 looks this:
error FS0039: The record label 'With' is not defined.
Output with F# 4.1 will look like this:
error FS1129: The record label 'With' is not defined. Maybe you want one of the following:
In this case, a suggestion is made based on record labels that the compiler already knows to be defined. These kinds of improvements are helpful for people new to F#, where the impact of more arcane error messages can negatively influence someone’s decision to keep using that language.
This is an ongoing process, and we’ll continue to see improvements to error messages even past F# 4.1. If you notice an error message that you feel is hard to understand, please create an issue on the Visual F# repository with an example and a proposed improvement! We’d love to improve error messages further.
Issue tracking improvements: https://github.com/Microsoft/visualfsharp/issues/1103
Trying these new features out
The best way to try out F# 4.1 is to use pre-releases of the F# compiler tools for .NET Core, as described earlier in this blog post. You can also build the current Visual F# Compiler from source..
Rolling out F# 4.1
We are partnering with the F# community, including other groups at Microsoft, to ensure that F# 4.1 support is rolled out across the very wide range of tooling available for F# 4.1.
- The Xamarin team at Microsoft are actively incorporating F# 4.1 support into the F# support in Xamarin Studio.
- The Mono packaging team is updating the packages available to include F# 4.1.
- The F# community is integrating F# 4.1 support in the F# Compiler Service component, used by many editing and compilation tools.
- We are working with the F# community to help update the F# support in the Visual F# Power Tools and ensure it works smoothly with the next release of Visual Studio.
- The F# community are already actively integrating support for F# 4.1 into support for Visual Studio Code and Atom through the Ionide project.
- The F# community are integrating support for F# 4.1 into many other tools, include Fable, an F# to ECMAScript transpiler, and into the F# support for Emacs and Vim.
The Visual F# Tools
Note: The timeline for this support may be Update 1 of Visual Studio “15” rather than RTM. There is no definite date at this time.
The Visual F# Tools for F# 4.1 will be updated to include support for editing and compiling .NET Standard projects, in addition to .NET Framework projects. .NET Standard is the common subset of APIs between .NET Core, .NET Framework, and Mono. To learn more about the .NET Standard, read The .NET Standard Library. The Visual F# Tools will also include incremental fixes and integration with the new Visual Studio installation process.
The final area for F# 4.1 is integrating the F# language service with Roslyn Workspaces. This will modernize the F# IDE experience in Visual Studio, making it comparable to C# and Visual Basic and opening the doors to future IDE innovation. Once this work is completed, many IDE features will “light up” automatically, such as IntelliSense filters.
For the uninitiated, a language service is a way to expose components of a compiler to tooling. For a simple example, when you “dot” into a class and see all the available methods, properties, and other types, the tooling has inspected that component of the Syntax Tree which corresponds to your code, gathered available type information, and displayed it for you. This is possible with the language service of the programming language you are using.
Because F#, the Visual F# Tools, and Roslyn are all open source, future productivity features in the F# editing experience for Visual Studio can also be added by the F# community.
The upcoming release described in this blog post is an exciting step in Microsoft’s tools for F#, featuring significant language improvements and cross-platform .NET Core support. Support for F# 4.1 is also being rolled out across the F# world. We invite you to use the preliminary versions of these language and tooling features today through alpha versions of our cross-platform compiler toolchain for .NET Core. Whether doing .NET Framework or .NET Core development, we invite you to help contribute to the development of the tools on the Visual F# GitHub repository.
Cheers, and happy F#-ing!
– The Visual F# Team