You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/fsharp/whats-new/fsharp-9.md
+74-50Lines changed: 74 additions & 50 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -23,7 +23,8 @@ For more details, watch out for an [upcoming blog post about this feature](https
23
23
24
24
Here are some examples:
25
25
26
-
<pre><codeclass="language-fsharp">// Declared type at let-binding
26
+
```fsharp
27
+
// Declared type at let-binding
27
28
let notAValue: string | null = null
28
29
29
30
let isAValue: string | null = "hello world"
@@ -54,64 +55,71 @@ let findOrNull (index: int) (list: 'T list) : 'T | null when 'T : not struct =
54
55
match List.tryItem index list with
55
56
| Some item -> item
56
57
| None -> null
57
-
</code></pre>
58
+
```
58
59
59
60
### Discriminated union `.Is*` properties
60
61
61
62
Discriminated unions now have auto-generated properties for each case, allowing you to check if a value is of a particular case. For example, for the following type:
62
63
63
-
<pre><codeclass="language-fsharp">type Contact =
64
+
```fsharp
65
+
type Contact =
64
66
| Email of address: string
65
67
| Phone of countryCode: int * number: string
66
68
67
69
type Person = { name: string; contact: Contact }
68
-
</code></pre>
70
+
```
69
71
70
72
Previously, you would have to write something like:
71
73
72
-
<pre><codeclass="language-fsharp">let canSendEmailTo person =
74
+
```fsharp
75
+
let canSendEmailTo person =
73
76
match person.contact with
74
77
| Email _ -> true
75
78
| _ -> false
76
-
</code></pre>
79
+
```
77
80
78
81
Now, you can instead write:
79
82
80
-
<pre><codeclass="language-fsharp">let canSendEmailTo person =
83
+
```fsharp
84
+
let canSendEmailTo person =
81
85
person.contact.IsEmail
82
-
</code></pre>
86
+
```
83
87
84
88
### Partial active patterns can return `bool` instead of `unit option`
85
89
86
90
Previously, partial active patterns would return `Some ()` to indicate a match and `None` otherwise. Now, they can also return `bool`.
87
91
88
92
For example, the active pattern for the following:
### Prefer extension methods to intrinsic properties when arguments are provided
109
116
110
117
To align with a pattern seen in some .NET libraries, where extension methods are defined with the same names as intrinsic properties of a type, F# will now resolve these extension methods instead of failing the type check.
111
118
112
119
Example:
113
120
114
-
<pre><codeclass="language-fsharp">type Foo() =
121
+
```fsharp
122
+
type Foo() =
115
123
member val X : int = 0 with get, set
116
124
117
125
[<Extension>]
@@ -122,19 +130,20 @@ type FooExt =
122
130
let f = Foo()
123
131
124
132
f.X(1) // We can now call the extension method to set the property and chain further calls
125
-
</code></pre>
133
+
```
126
134
127
135
### Support for empty-bodied computation expressions
128
136
129
137
F# now supports empty [computation expressions](https://learn.microsoft.com/dotnet/fsharp/language-reference/computation-expressions).
Full name: Microsoft.FSharp.Collections.ListModule.map
180
191
Assembly: FSharp.Core.dll
181
-
</code></pre>
192
+
```
182
193
183
194
### Allow #nowarn to support the FS prefix on error codes to disable warnings
184
195
@@ -187,14 +198,15 @@ Previously, when you wanted to disable a warning and wrote `#nowarn "FS0057"`, y
187
198
Now, you won't have to spend time figuring that out because the warning numbers are accepted even with the prefix.
188
199
189
200
All of these will now work:
190
-
<pre><codeclass="language-fsharp">#nowarn 57
201
+
```fsharp
202
+
#nowarn 57
191
203
#nowarn 0057
192
204
#nowarn FS0057
193
205
194
206
#nowarn "57"
195
207
#nowarn "0057"
196
208
#nowarn "FS0057"
197
-
</code></pre>
209
+
```
198
210
199
211
It's probably a good idea to stick to the same style throughout your project.
200
212
@@ -203,26 +215,28 @@ It's probably a good idea to stick to the same style throughout your project.
203
215
F# will now emit a warning when you put the `[<TailCall>]` attribute somewhere it doesn't belong. While it has no effect on what the code does, it could confuse someone reading it.
let rec someRecLetBoundValue = nameof(someRecLetBoundValue)
214
-
</code></pre>
227
+
```
215
228
216
229
### Enforce attribute targets
217
230
218
231
The compiler now correctly enforces the `AttributeTargets` on let values, functions, union case declarations, implicit constructors, structs, and classes. This can prevent some hard-to-notice bugs, such as forgetting to add the unit argument to an Xunit test.
219
232
220
233
Previously, you could have written:
221
234
222
-
<pre><codeclass="language-fsharp">[<Fact>]
235
+
```fsharp
236
+
[<Fact>]
223
237
let ``this test always fails`` =
224
238
Assert.True(false)
225
-
</code></pre>
239
+
```
226
240
227
241
Run the tests with `dotnet test` and they would pass. Since the test function is not actually a function, it is ignored by the test runner.
228
242
@@ -246,46 +260,51 @@ There are four functions (each with three variants) available:
246
260
247
261
The shuffle functions return a new collection of the same type and size, with each item in a randomly mixed position. The chance to end up in any position is weighted evenly on the length of the collection.
Sample selects N elements from the input collection in random order, without allowing elements to be selected more than once. N cannot be greater than the collection length.
For a full list of functions and their variants, see ([RFC #1135](https://github.com/fsharp/fslang-design/blob/main/RFCs/FS-1135-random-functions-for-collections.md)).
280
298
281
299
### Parameterless constructor for `CustomOperationAttribute`
282
300
283
301
This makes it easier to create a custom operation for a computation expression builder. It will use the name of the method instead of having to explicitly name it (when in most cases the name matches the method name already).
This makes it easier to use the F# immutable collections from C#, for example when you need their structural equality, which `System.Collections.Immutable` collections don't have.
305
324
@@ -334,7 +353,7 @@ Now, there is an opt-in fix for this behavior available via the `--realsig+` com
@@ -353,7 +373,7 @@ let ids = Array.init 1000 MyId
353
373
let missingId = MyId -1
354
374
355
375
// used to box 1000 times, doesn't box anymore
356
-
let _ = ids |> Array.contains missingId</code></pre>
376
+
let _ = ids |> Array.contains missingId```
357
377
358
378
You can read all the details here: [F# Developer Stories: How we’ve finally fixed a 9-year-old performance issue](https://devblogs.microsoft.com/dotnet/fsharp-developer-stories-how-weve-finally-fixed-a-9yearold-performance-issue/).
359
379
@@ -367,15 +387,18 @@ The compiler now generates optimized code for more instances of `start..finish`
367
387
368
388
This leads to anywhere from 1.25× up to 8× speed up in loops:
369
389
370
-
<pre><codeclass="language-fsharp">for … in start..finish do …</code></pre>
<pre><codeclass="language-fsharp">[for n in start..finish -> f n]</code></pre>
400
+
```fsharp
401
+
[for n in start..finish -> f n]```
379
402
380
403
### Optimized `for x in xs -> …` in list and array comprehensions
381
404
@@ -392,8 +415,9 @@ This previously opt-in feature has been thoroughly tested and is now enabled by
392
415
Sometimes extra parentheses are used for clarity, but sometimes they are just noise. For the latter case, you now get a code fix in Visual Studio to remove them.
393
416
394
417
For example:
395
-
<pre><codeclass="language-fsharp">let f (x) = x // -> let f x = x
396
-
let _ = (2 * 2) + 3 // -> let _ = 2 * 2 + 3</code></pre>
418
+
```fsharp
419
+
let f (x) = x // -> let f x = x
420
+
let _ = (2 * 2) + 3 // -> let _ = 2 * 2 + 3```
397
421
398
422
### Custom Visualizer support for F# in Visual Studio
0 commit comments