Facilitating the spread of knowledge and innovation in professional software development



Choose your language

InfoQ Homepage News F# 4.6 Introduces Anonymous Record Types

F# 4.6 Introduces Anonymous Record Types


The next release of F#, F# 4.6, will most notably bring anonymous record types and structs to the language, along with a few additions to the standard library.

Anonymous record types remove the need to provide a name for a record type and bring a bit of structural typing to an otherwise strictly nominal language.

Although they are unlikely to fundamentally change how you write F# code, they do fill many smaller gaps F# programmers have encountered over time, and can be used for succinct data manipulation that was not previously possible.

The following snippet shows how to define and call a function that takes an anonymous record and how equality works:

let foo (args: {| a: Int; b: Int |}) =

foo {| a=2; b=4 |}

{| a = 1+1 |} = {| a = 2 |} // true
{| a = 1+1 |} > {| a = 1 |} // true

{| a = 1+1 |} = {| a = 2;  b = 1|} // error, record type mismatch

It is worth noting that anonymous records are at their heart still nominal types and thus do not support structural sub-typing. This has the effect that pattern matching cannot be used over them.

As mentioned, you can also define anonymous structs, which differ from records in that they are allocated on the stack, using the struct {| ... |} syntax. Two anonymous records or structs are recognized as belonging to the same type only if the label fields match exactly. For example, a copy-and-update expression will generate a different anonymous record type:

let data = {| X = 1; Y = 2 |}
let expandedData = {| data with Y = 3 |} // {| X:Int; Y:Int |}
let expandedData' = {| data with Z = 3 |} // {| X:Int; Y:Int; Z:Int |}

You can also extend a normal record into an anonymous record:

type R1 = { X: int }
let r1 = { X=1 }

let data1 = {| r1 with Y=1 |} // {| X:Int; Y:Int |}

One useful use of anonymous record types is when serializing/deserializing lightweight JSON data, since an anonymous record type definition can be used as a type specification:

let networkData = "{\"age\":28,\"name\":\"Phillip\"}"
let person = JsonConvert.DeserializeObject<{|name: string; age: int|}>(str)

Another scenario where anonymous record types will simplify F# syntax is with record types that are mutually recursive, as the following example shows:

type FullName = { FirstName: string; LastName: string }
type Employee =
    | Engineer of FullName
    | Manager of {| Name: FullName; Reports: Employee list |}
    | Executive of {| Name: FullName; Reports: Employee list; Assistant: Employee |}

In F# 4.5, you would use the following syntax with named record types:

type FullName = { FirstName: string; LastName: string }
type Employee =
    | Engineer of FullName
    | Manager of Manager
    | Executive of Executive

and Manager = { Name: FullName; Reports: Employee list }

and Executive = { Name: FullName; Reports: Employee list; Assistant: Employee }

On the standard library front, F# 4.6 includes the following improvements:

  • ValueOptions, struct-based Option type introduced in F# 4.5, is now on-a-par with the Option type thanks to support for DebuggerDisplay, IsNone, IsSome, None, Some, op_Implicit, and ToString.

  • List, Array, and Seq support tryExactlyOne method, which works like exactlyOne but returning an option type wrapping the only element of the collection or None if zero or more than one elements are present.

F# 4.6 is available in Visual Studio 2019 Preview 2 and requires the .NET SDK 2.1.6xx or 2.2.6xx preview of the .NET SDK.

We need your feedback

How might we improve InfoQ for you

Thank you for being an InfoQ reader.

Each year, we seek feedback from our readers to help us improve InfoQ. Would you mind spending 2 minutes to share your feedback in our short survey? Your feedback will directly help us continually evolve how we support you.

Take the Survey

Rate this Article


Hello stranger!

You need to Register an InfoQ account or or login to post comments. But there's so much more behind being registered.

Get the most out of the InfoQ experience.

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Community comments

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p


Is your profile up-to-date? Please take a moment to review and update.

Note: If updating/changing your email, a validation request will be sent

Company name:
Company role:
Company size:
You will be sent an email to validate the new email address. This pop-up will close itself in a few moments.