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/optimizations-equality.md
+15-20
Original file line number
Diff line number
Diff line change
@@ -11,12 +11,12 @@ This spec is about the semantics and performance of the following coding constru
11
11
12
12
It is also about the semantics and performance of uses of the following `FSharp.Core` constructs which, after inlining, generate code that contains an equality check at the specific `EQTYPE`
13
13
*`HashIdentity.Structural<'T>`
14
-
*`{Array,Seq,List}.contains`
15
-
*`{Array,Seq,List}.countBy`
14
+
*`{Array,Seq,List}.contains`
15
+
*`{Array,Seq,List}.countBy`
16
16
*`{Array,Seq,List}.groupBy`
17
-
*`{Array,Seq,List}.distinct`
18
-
*`{Array,Seq,List}.distinctBy`
19
-
*`{Array,Seq,List}.except`
17
+
*`{Array,Seq,List}.distinct`
18
+
*`{Array,Seq,List}.distinctBy`
19
+
*`{Array,Seq,List}.except`
20
20
21
21
All of which have implied equality checks. Some of these operations are inlined, see below, which in turn affects the semantics and performance of the overall operation.
22
22
@@ -203,10 +203,9 @@ let f (x: float32) (y: float32) = (x = y)
203
203
204
204
* Semantics: User expects call to `IEquatable<T>` if present, but F# spec says call `this.Equals(box that)`, in practice these are the same
* Perf today: hand-optimized ([here](https://github.com/dotnet/fsharp/blob/611e4f350e119a4173a2b235eac65539ac2b61b6/src/FSharp.Core/prim-types.fs#L1562)) for some primitive element types ✅ but boxes each element if "other" is struct or generic, see Problem3 ❌, Problem4 ❌
264
+
* Compilation today: either ``FSharpEqualityComparer_PER`1<uint8[]>::get_EqualityComparer().Equals(...)`` or ``FSharpEqualityComparer_PER`1<T[]>::get_EqualityComparer().Equals(...)``
265
+
* Perf today: good ✅
267
266
*[sharplab for `byte[]`](https://sharplab.io/#v2:DYLgZgzgPgsAUMApgFwARlQCgB4lQIwE9lEBtAXQEpVDUBeLbemy+IA=)
268
-
* Note: ([#16615](https://github.com/dotnet/fsharp/pull/16615)) will improve this compiling to either ``FSharpEqualityComparer_PER`1<uint8[]>::get_EqualityComparer().Equals(...)`` or ``FSharpEqualityComparer_PER`1<T[]>::get_EqualityComparer().Equals(...)``
269
267
270
268
### F# large reference record/union type
271
269
@@ -282,28 +280,25 @@ Here "tiny" means the compiler-generated structural equality IS inlined.
282
280
283
281
* Semantics: User expects structural by default
284
282
* Perf expected: User expects perf is sum of constituent parts, type-specialized if generic
285
-
* Compilation today: flattened, calling `GenericEqualityERIntrinsic` on struct and generic fields
286
-
* Perf today: boxes on struct and generic fields, see Problem3 ❌, Problem4 ❌
287
-
* Note: [#16615](https://github.com/dotnet/fsharp/pull/16615) will help, compiling to ``FSharpEqualityComparer_ER`1<!a>::get_EqualityComparer().Equals(...)`` on struct and generic fields
* Semantics: User expects the PER equality semantics of whatever `'T` actually is
292
289
* Perf expected: User expects no boxing
293
-
* Compilation today: `GenericEqualityERIntrinsic`
294
-
* Perf today: boxes if `'T` is any non-reference type (Problem4 ❌)
295
-
* Note: [#16615](https://github.com/dotnet/fsharp/pull/16615) will improve this compiling to ``FSharpEqualityComparer_ER`1<!a>::get_EqualityComparer().Equals(...)``
* Note: [#16615](https://github.com/dotnet/fsharp/pull/16615) will compile to ``FSharpEqualityComparer_ER`1<!a>::get_EqualityComparer().Equals(...)`` and avoid boxing in many cases
0 commit comments