F# is developed in the open by the F# Software Foundation community and Microsoft; each language change since F# 4.0 has an RFC in the fslang-design repository. The language version is chosen with <LangVersion> in the project (or --langversion); the compiler checks each newer feature against it. The table below is built from the language-feature table of the compiler (F# 4.6 onward), the “What’s new” pages of the documentation (F# 4.5, 4.6, 4.7, 5, 6, 9, 10 and 11), the RFC folders and, for the oldest versions, from memory, which is marked.
Releases
| Version | What it added or changed |
|---|---|
| 1.0 to 3.1 | (from memory, not in the downloaded sources) the first versions: ML-style functional core, classes and interfaces, light syntax, workflows (async), units of measure; 2.0 shipped with Visual Studio 2010; 3.0 added type providers and query expressions (the specification confirms that query expressions came with 3.0); 3.1 added small language fixes. |
| 4.0 | RFC folder items: class names usable as functions (constructors as first-class values), the auto quotation of arguments, an extended if grammar, extension property initialisers, interfaces at several instantiations, static method arguments for type providers, units of measure in printf, additions to the List, Seq and Array modules. (The rest of 4.0, such as mutable values captured by closures becoming ref automatically, is from memory.) |
| 4.1 | struct tuples, struct records, struct discriminated unions; the Result type; underscores in numeric literals; byref returns; fixed; the unreserved keywords (method constructor atomic eager object recursive functor measure volatile); caller information attributes; module rec and namespace rec (mutually referential types and modules in one scope); implicit Module suffix; Option and Map.count additions; ToString overridden for unions and records; consistent tuple types. |
| 4.5 | Span and byref-like structs, inref and outref, readonly structs, void pointers, match!, relaxed upcasting in array, list and sequence expressions, public enum cases, relaxed indentation for array and list arguments. |
| 4.6 | anonymous records ({| A = 1 |}); ValueOption functions. The first language version the current compiler accepts. |
| 4.7 | implicit yield in list, array and sequence expressions; wildcard self identifiers (member _.X); indentation relaxations; the language-version switch. |
| 5 (with .NET 5) | #r "nuget: …" in scripts; string interpolation $"…"; nameof; open type; consistent slicing for built-in types and fixed-index slices for 3D and 4D arrays; quotation improvements; applicative computation expressions (and!); interfaces implemented at different generic instantiations; default interface members consumed; simplified interop with nullable value types. Previews: reverse indexes, overloads of custom keywords. |
| 6 (with .NET 6) | task { … }; expr[idx] indexing; struct representation for partial active patterns; overloaded custom operations; relaxed as patterns; more implicit conversions (up-casts, integer widening, op_Implicit) with optional warnings 3388, 3389, 3391, 3395; formatting for binary numbers; discards in use bindings; InlineIfLambda; resumable code; insertAt removeAt updateAt insertManyAt removeManyAt; Map.Keys and Values; more NativePtr intrinsics; more numeric types with unit annotations. |
| 7 | (RFC folder) simpler constrained call syntax; SRTP type without whitespace; Map.minKeyValue and maxKeyValue; Result module parity with Option; interfaces with static abstract members; lower-case union cases when RequireQualifiedAccess is set; init-only and required properties; NoCompilerInlining; arithmetic in literals. |
| 8 | (RFC folder) warning on recursive functions that are not tail-recursive (the TailCall check); extended fixed bindings; static members in interfaces; shorthand anonymous unary functions (_.Name); better interpolated triple-quoted strings (the $$""" forms); try … with in sequence expressions; constraint intersection syntax. The oldest language version the current compiler supports without an override. |
| 9 (with .NET 9) | nullable reference types (string | null, switched on with <Nullable>enable</Nullable>); union .Is* properties; bool-returning partial active patterns; extension methods preferred to properties when arguments are given; empty-bodied computation expressions; hash directives that take non-string arguments (#nowarn 0070, #time on); #nowarn with the FS prefix; a warning for [<TailCall>] on non-recursive functions; enforced attribute targets; random functions for collections (shuffle, choice, choices, sample); C# collection expression support for lists and sets. |
| 10 (with .NET 10) | scoped #nowarn and #warnon (a warning off for a stretch of lines); access modifiers on auto-property accessors; ValueOption optional parameters; tail calls in computation expressions (ReturnFromFinal, YieldFromFinal); typed let! and use! bindings without parentheses; _ in use!; pseudo-nested modules in types rejected; deprecation warning for omitted seq; attribute target enforcement; and! in task expressions; better trimming; type subsumption cache; parallel compilation in preview; object expressions without overrides; decimal constants. |
| 11 (with .NET 11) | record spreads ({ ...a; X = 1 } and { ...Type } in type definitions); extension members for generic algorithms, operators and tuples; direct delegates keep the handler’s contract; reuse of XML documentation; debugging inline functions in non-optimised builds; async and task helpers for cancellation and limited concurrency; FSharp.Core built for modern .NET; Native AOT friendly text and 2D arrays; parallel compilation by default; #elif; #version in F# Interactive; #: host lines; protected base fields readable in closures; default implementations of derived interfaces; error FS3888 for a missing signature attribute. |
| 11.2 | the compiler’s feature table also has a language version 11.2, which is the default of the source read: more concrete tie-breaker in overload resolution, OverloadResolutionPriority, runtime async, constructing a record with its all-fields constructor (MyRecord(a, b)), required named arguments (RequireNamedArgumentsAt), reraise in computation expressions, extension-constraint solutions. In the .NET 11.0.100 SDK these need --langversion:preview; 11.2 is planned as the default of SDK 11.0.200 (compiler-options page). The non-strict indentation mode has been removed, also from earlier numbered language modes. |
| preview | from-end slicing (FromEndSlicing) is still listed as an unfinished preview feature in the compiler’s table. |
The language versions the compiler recognises are 4.6, 4.7, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0 and 11.2, plus preview, default, latest and latestmajor. Versions before 8.0 are accepted only with an override of the support check.
What the viewer does about versions
The viewer does not know which version a file is written for. Newer forms are coloured when they appear: $$""" strings (5 and 8), and! (5), #elif (11), #: lines (11), _.Name shorthand (8, _ is plain), {| |} anonymous records (4.6) and ... spreads (11, the dots are plain).
Not described
Known, not yet covered
- Reference: F# 7 and 8 are taken from the RFC folder names only, because the documentation’s pages for them just point to the release blog posts, which were not read; the RFCs of 4.0 and 4.1 were listed, not read. The F# 4.0 notes beyond the RFC names, and all of F# 1.0 to 3.1, are from memory.
- Reference: release dates are not given (the documentation names the .NET version only for F# 5, 6, 9, 10 and 11 pages); the RFCs of 9 to 11 were not read in full.
Unknown
- Reference: which of the compiler’s 11.2 features are released and which are still on the main branch: the table read is the main branch of
dotnet/fsharpat the time of download.
See also
- Overview – the file kinds and where each is described
- Clojure: versions and history and Racket: history and versions