Open En3Tho opened 3 years ago
Yeah, replacing String.op_Equality(str1, null)
to str1 ceq null
makes output IL smaller and makes jit's life easier during inlining.
@En3Tho Could you include a micro-benchmark perf result or x64 ASM code?
Method | Job | Runtime | value | Mean | Error | StdDev | Median | Code Size | Allocated |
---|---|---|---|---|---|---|---|---|---|
CompareStringViaEquals | .NET 5.0 | .NET 5.0 | 1.4297 ns | 0.0044 ns | 0.0034 ns | 1.4299 ns | 63 B | - | |
CompareStringViaRefEquals | .NET 5.0 | .NET 5.0 | 0.0077 ns | 0.0105 ns | 0.0098 ns | 0.0024 ns | 10 B | - |
[<DisassemblyDiagnoser>]
[<MemoryDiagnoser>]
[<SimpleJob(RuntimeMoniker.Net50)>]
[<SimpleJob(RuntimeMoniker.Net60)>]
type Benchmark() =
[<Benchmark>]
[<Arguments("")>]
member _.CompareStringViaEquals(value: string) = value = null
[<Benchmark>]
[<Arguments("")>]
member _.CompareStringViaRefEquals(value: string) = Object.ReferenceEquals(value, null)
I thought that JIT could recognize this pattern and this is IL-only problem but sadly, no.
= null
is not good practice. What about isNull
though?
https://latkin.org/blog/2015/05/18/null-checking-considerations-in-f-its-harder-than-you-think/
It's a perfectly good practice for anybody coming from another language. For example, C# has string == null. A person would expect the very similar thing to work in F#. And if it's a bad one, F# should have an analyzer for this. Althought I don't really see why it's a bad practice honestly. Somethimes you need to check for null only, not for NullOrEmpty or Whatespace or whatever
Consider those 2 methods:
If we compare outputs of F# and C# compilers in IL we can see that C# does a simple nullpointer check while F# calls to String.Equals method
F# version:
C# version:
Note that C# on top of this reverses condition and useful work resulting in better jit codegen. Coincidentally this is even more simplified repro for (https://github.com/dotnet/fsharp/issues/12138).