Open matthewcrews opened 2 years ago
F# has had a lot of trouble doing equality and comparison cleanly. PRs have come and gone including https://github.com/dotnet/fsharp/pull/5112, https://github.com/dotnet/fsharp/pull/6175.
If https://github.com/dotnet/fsharp/pull/6175 gets resurrected it may be the best approach to the performance issue.
Fixing the type issue (moving to generic IComparable<T>
instead of IComparable
) is this suggestion: https://github.com/fsharp/fslang-suggestions/issues/816 .
This suggestion here is a workaround that uses an IComparer<'T>
, not because a different comparison logic is needed, but to avoid the poor performance of F# comparison when creating sets. However it is too small. We would need similar workarounds for all uses of comparison in F#. Better to address the problem entirely and then no workarounds are needed.
I'm completely fine with closing this one and resurrecting another. I created this per Don's request on Twitter.
If something could be done, it would be greatly appreciated.
It looks like dotnet/fsharp#6175 is the best approach for this problem. I would be immensely grateful if it was brought back.
That one is the best overall approach, yeah. Maybe @tihan could chime in on it a bit, but my understanding is that it is very tricky work with a high risk of breaking changes, which is why it was put on ice
This suggestion here is a workaround that uses an IComparer<'T>, not because a different comparison logic is needed, but to avoid the poor performance of F# comparison when creating sets.
Well what if different comparison logic is needed? I had this case recently when trying to use System.Type
as a key in a Map. Furthermore, this approach seems much simpler and safer than https://github.com/dotnet/fsharp/pull/6175, but also doesn't preclude that change from landing one day.
Here's a problem though: how do you handle, for example, Set.union s1 s2
when s1
and s2
use different comparers?
@cartermp my understanding is that it is very tricky work with a high risk of breaking changes
I am very enthusiastic about the ability of flags to allow F# to move forwards with less concern for breaking changes. Reflection-free string functions will live behind a flag or attribute, and in https://github.com/dotnet/fsharp/pull/6175 the dangerous stuff lives behind --optimize:equality
.
We may need an RFC to specify exactly what flags we need. Something like --equalitycomparison [classic|optimized|generic]
, where classic preserves existing behaviour, optimized (--optimize:equality
as defined in the PR) and generic uses IEquatable<'T>.Equals('T)
always.
Here's a problem though: how do you handle, for example,
Set.union s1 s2
whens1
ands2
use different comparers?
we get a new type
Set<Record, CustomRecordComparer> != Set<Record>
@BashkaMen We'd have to duplicate the entire Set module though.
Add overload for creating Set/Map that includes an IComparer<'T>
I propose we add an overload for the creation of
Set<'T>
andMap<'K, 'V>
which takes anIComparer<'T>
to override the default comparison behavior of these two collections. Where I believe this would add the most value is in the case of structs that currently get boxed during comparison leading to performance degradation.The existing way of approaching this problem in F# is to use the built-in comparison functionality in the F# language.
You can see from the benchmarks in this repo. The
Struct
andCustomStruct
versions are allocating more memory than the default Record.If this proposal does not address the GC/performance problem then I suggest we discard it since it is the main concern.
Pros and Cons
The advantages of making this adjustment to F# are that we reduce the GC associated with boxing structs unnecessarily.
The disadvantages of making this adjustment to F# are added complexity of the F# Core library and therefore more code to maintain.
Extra information
Estimated cost (XS, S, M, L, XL, XXL): M
Related suggestions: (put links to related suggestions here)
Affidavit (please submit!)
Please tick this by placing a cross in the box:
Please tick all that apply:
For Readers
If you would like to see this issue implemented, please click the :+1: emoji on this issue. These counts are used to generally order the suggestions by engagement.