Skip to content

Commit 0c1ede7

Browse files
0101gewarren
andauthored
Apply suggestions from code review
Co-authored-by: Genevieve Warren <[email protected]>
1 parent abf85dd commit 0c1ede7

File tree

1 file changed

+46
-36
lines changed

1 file changed

+46
-36
lines changed

docs/fsharp/whats-new/fsharp-9.md

Lines changed: 46 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ type Contact =
6969
type Person = { name: string; contact: Contact }
7070
```
7171

72-
Previously, you would have to write something like:
72+
Previously, you had to write something like:
7373

7474
```fsharp
7575
let canSendEmailTo person =
@@ -87,7 +87,7 @@ let canSendEmailTo person =
8787

8888
### Partial active patterns can return `bool` instead of `unit option`
8989

90-
Previously, partial active patterns would return `Some ()` to indicate a match and `None` otherwise. Now, they can also return `bool`.
90+
Previously, partial active patterns returned `Some ()` to indicate a match and `None` otherwise. Now, they can also return `bool`.
9191

9292
For example, the active pattern for the following:
9393
```fsharp
@@ -96,7 +96,8 @@ match key with
9696
| CaseInsensitive "bar" -> ...
9797
```
9898

99-
Would previously be written as:
99+
Was previously written as:
100+
100101
```fsharp
101102
let (|CaseInsensitive|_|) (pattern: string) (value: string) =
102103
if String.Equals(value, pattern, StringComparison.OrdinalIgnoreCase) then
@@ -114,7 +115,7 @@ let (|CaseInsensitive|_|) (pattern: string) (value: string) =
114115

115116
### Prefer extension methods to intrinsic properties when arguments are provided
116117

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.
118+
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# now resolves these extension methods instead of failing the type check.
118119

119120
Example:
120121

@@ -134,7 +135,7 @@ f.X(1) // We can now call the extension method to set the property and chain fur
134135

135136
### Support for empty-bodied computation expressions
136137

137-
F# now supports empty [computation expressions](https://learn.microsoft.com/dotnet/fsharp/language-reference/computation-expressions).
138+
F# now supports empty [computation expressions](../language-reference/computation-expressions.md).
138139

139140
<pre class="language-fsharp"><code>let xs = seq { } // Empty sequence```
140141

@@ -208,13 +209,13 @@ All of these will now work:
208209
#nowarn "FS0057"
209210
```
210211

211-
It's probably a good idea to stick to the same style throughout your project.
212+
It's a good idea to use the same style throughout your project.
212213

213214
### Warning about TailCall attribute on non-rec functions or let-bound values
214215

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.
216+
F# now emits 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.
216217

217-
For example, these will now emit a warning:
218+
For example, these usages will now emit a warning:
218219
```fsharp
219220
[&lt;TailCall&gt;]
220221
let someNonRecFun x = x + x
@@ -230,15 +231,15 @@ let rec someRecLetBoundValue = nameof(someRecLetBoundValue)
230231

231232
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.
232233

233-
Previously, you could have written:
234+
Previously, you could write:
234235

235236
```fsharp
236237
[&lt;Fact&gt;]
237238
let ``this test always fails`` =
238239
Assert.True(false)
239240
```
240241

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.
242+
When you ran the tests with `dotnet test`, they would pass. Since the test function is not actually a function, it was ignored by the test runner.
242243

243244
Now, with correct attribute enforcement, you will get an `error FS0842: This attribute is not valid for use on this language element`.
244245

@@ -248,17 +249,17 @@ Now, with correct attribute enforcement, you will get an `error FS0842: This att
248249

249250
The `List`, `Array`, and `Seq` modules have new functions for random sampling and shuffling. This makes F# easier to use for common data science, machine learning, game development, and other scenarios where randomness is needed.
250251

251-
All functions have variants using:
252+
All functions have the following variants:
252253

253-
* An implicit thread-safe shared [`Random`](https://learn.microsoft.com/dotnet/api/system.random) instance
254-
* Taking a `Random` instance as an argument
255-
* Taking a custom `randomizer` function, which should return a float value greater than or equal to 0.0 and less than 1.0
254+
* One that uses an implicit, thread-safe, shared <xref:System.Random> instance
255+
* One that takes a `Random` instance as an argument
256+
* One that takes a custom `randomizer` function, which should return a float value greater than or equal to 0.0 and less than 1.0
256257

257-
There are four functions (each with three variants) available:
258+
There are four functions (each with three variants) available: `Shuffle`, `Choice`, `Choices`, and `Sample`.
258259

259260
#### Shuffle
260261

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.
262+
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.
262263

263264
```fsharp
264265
let allPlayers = [ "Alice"; "Bob"; "Charlie"; "Dave" ]
@@ -269,7 +270,7 @@ For arrays, there are also `InPlace` variants that shuffle the array in place.
269270

270271
#### Choice
271272

272-
The choice functions return a single random element from the given collection. The random choice is weighted evenly on the size of the collection.
273+
The `Choice` functions return a single random element from the given collection. The random choice is weighted evenly on the size of the collection.
273274

274275
```fsharp
275276
let allPlayers = [ "Alice"; "Bob"; "Charlie"; "Dave" ]
@@ -278,7 +279,7 @@ let randomPlayer = allPlayers |> List.randomChoice // "Charlie"
278279

279280
#### Choices
280281

281-
Choices select N elements from the input collection in random order, allowing elements to be selected more than once.
282+
The `Choices` functions select N elements from the input collection in random order, allowing elements to be selected more than once.
282283

283284
```fsharp
284285
let weather = [ "Raining"; "Sunny"; "Snowing"; "Windy" ]
@@ -287,7 +288,7 @@ let forecastForNext3Days = weather |> List.randomChoices 3 // [ "Windy"; "Snowin
287288

288289
#### Sample
289290

290-
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.
291+
The `Sample` functions select 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.
291292

292293
```fsharp
293294
let foods = [ "Apple"; "Banana"; "Carrot"; "Donut"; "Egg" ]
@@ -298,11 +299,11 @@ For a full list of functions and their variants, see ([RFC #1135](https://github
298299

299300
### Parameterless constructor for `CustomOperationAttribute`
300301

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).
302+
This constructor makes it easier to create a custom operation for a computation expression builder. It uses the name of the method instead of having to explicitly name it (when in most cases the name matches the method name already).
302303

303304
```fsharp
304305
type FooBuilder() =
305-
[&lt;CustomOperation&gt;] // Previously would have to be [&lt;CustomOperation("bar")&gt;]
306+
[&lt;CustomOperation&gt;] // Previously had to be [&lt;CustomOperation("bar")&gt;]
306307
member _.bar(state) = state
307308
```
308309

@@ -312,21 +313,23 @@ When using F# lists and sets from C#, you can now use collection expressions to
312313

313314
Instead of:
314315

315-
<pre><code class="language-csharp">FSharpSet&lt;int&gt; mySet = SetModule.FromArray([1, 2, 3]);
316+
```csharp
317+
FSharpSet&lt;int&gt; mySet = SetModule.FromArray([1, 2, 3]);
316318
```
317319

318320
You can now write:
319321

320-
<pre><code class="language-csharp">FSharpSet&lt;int&gt; mySet = [ 1, 2, 3 ];
322+
```csharp
323+
FSharpSet&lt;int&gt; mySet = [ 1, 2, 3 ];
321324
```
322325

323-
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.
326+
Collection expressions make it easier to use the F# immutable collections from C#. You might want to use the F# collections when you need their structural equality, which <xref:System.Collections.Immutable> collections don't have.
324327

325328
## Quality of life improvements
326329

327330
### Parser recovery
328331

329-
There have been continuous improvements in parser recovery, meaning that tooling (e.g. syntax highlighting) still works with code when you're in the middle of editing it and it may not be syntactically correct at all times.
332+
There have been continuous improvements in parser recovery, meaning that tooling (for example, syntax highlighting) still works with code when you're in the middle of editing it and it might not be syntactically correct at all times.
330333

331334
For example, the parser will now recover on unfinished `as` patterns, object expressions, enum case declarations, record declarations, complex primary constructor patterns, unresolved long identifiers, empty match clauses, missing union case fields, and missing union case field types.
332335

@@ -335,22 +338,24 @@ For example, the parser will now recover on unfinished `as` patterns, object exp
335338
Diagnostics, or understanding what the compiler doesn't like about your code, are an important part of the user experience with F#. There are a number of new or improved diagnostic messages or more precise diagnostic locations in F# 9.
336339

337340
These include:
341+
338342
- Ambiguous override method in object expression
339343
- Abstract members when used in non-abstract classes
340-
- When a property has the same name as a discriminated union case
344+
- Property that has the same name as a discriminated union case
341345
- Active pattern argument count mismatch
342346
- Unions with duplicated fields
343347
- Using `use!` with `and!` in computation expressions
344348

345-
There is also a new compile-time error for classes with over 65,520 methods in generated [IL](https://learn.microsoft.com/dotnet/standard/managed-code#intermediate-language--execution). Such classes won't be loadable by the CLR and would result in a runtime error. (Not that you would ever really want to have so many methods, but there have been cases with generated code.)
349+
There is also a new compile-time error for classes with over 65,520 methods in generated [IL](../../standard/managed-code.md#intermediate-language--execution). Such classes aren't loadable by the CLR and would result in a run-time error. (Not that you would ever really want to have so many methods, but there have been cases with generated code.)
346350

347351
### Real visibility
348352

349-
There is a quirk with how F# generates assemblies that results in private members being written to [IL](https://learn.microsoft.com/dotnet/standard/managed-code#intermediate-language--execution) as internal. This allows inappropriate access to private members from non-F# projects that have access to an F# project via [`InternalsVisibleTo`](https://learn.microsoft.com/dotnet/api/system.runtime.compilerservices.internalsvisibletoattribute).
353+
There is a quirk with how F# generates assemblies that results in private members being written to [IL](../../standard/managed-code.md#intermediate-language--execution) as internal. This allows inappropriate access to private members from non-F# projects that have access to an F# project via [`InternalsVisibleTo`](xref:System.Runtime.CompilerServices.InternalsVisibleToAttribute).
350354

351355
Now, there is an opt-in fix for this behavior available via the `--realsig+` compiler flag. Try it in your solution to see if any of your projects depend on this behavior. You can add it to your `.fsproj` files like this:
352356

353-
<pre><code class="language-xml">&lt;PropertyGroup&gt;
357+
```xml
358+
<PropertyGroup>
354359
&lt;OtherFlags&gt;--realsig+&lt;/OtherFlags&gt;
355360
&lt;/PropertyGroup&gt;
356361
```
@@ -373,7 +378,8 @@ let ids = Array.init 1000 MyId
373378
let missingId = MyId -1
374379

375380
// used to box 1000 times, doesn't box anymore
376-
let _ = ids |> Array.contains missingId```
381+
let _ = ids |> Array.contains missingId
382+
```
377383

378384
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/).
379385

@@ -388,17 +394,20 @@ The compiler now generates optimized code for more instances of `start..finish`
388394
This leads to anywhere from 1.25× up to 8× speed up in loops:
389395

390396
```fsharp
391-
for … in start..finish do …```
397+
for … in start..finish do …
398+
```
392399

393400
List/array expressions:
394401

395402
```fsharp
396-
[start..step..finish]```
403+
[start..step..finish]
404+
```
397405

398406
and comprehensions:
399407

400408
```fsharp
401-
[for n in start..finish -> f n]```
409+
[for n in start..finish -> f n]
410+
```
402411

403412
### Optimized `for x in xs -> …` in list and array comprehensions
404413

@@ -417,16 +426,17 @@ Sometimes extra parentheses are used for clarity, but sometimes they are just no
417426
For example:
418427
```fsharp
419428
let f (x) = x // -> let f x = x
420-
let _ = (2 * 2) + 3 // -> let _ = 2 * 2 + 3```
429+
let _ = (2 * 2) + 3 // -> let _ = 2 * 2 + 3
430+
```
421431

422-
### Custom Visualizer support for F# in Visual Studio
432+
### Custom visualizer support for F# in Visual Studio
423433

424434
The debugger visualizer in Visual Studio now works with F# projects.
425435

426436
![debug visualizer](../media/whats-new/fsharp-9/vs-visualizer.gif)
427437

428438
### Signature tooltips shown mid-pipeline
429439

430-
Previously, no signature help was offered in a situation like the following, where a function in the middle of a pipeline already had a complex curried parameter (e.g., a lambda) applied to it. Now, the signature tooltip will show up for the next parameter (`state`):
440+
Previously, no signature help was offered in a situation like the following, where a function in the middle of a pipeline already had a complex curried parameter (for example, a lambda) applied to it. Now, the signature tooltip shows up for the next parameter (`state`):
431441

432442
![tooltip](../media/whats-new/fsharp-9/help.png)

0 commit comments

Comments
 (0)