We have a function converting things like Int32.TryParse
from using a byref to using an Option for the return value.
let inline ToOptionFunc refFunction x =
match refFunction x with
| true, value -> Some value
| false, _ -> None
Stuff like this stopped compiling in .NET Core with the new overloads to TryParse:
let Int32TryParse (x:string) =
ToOptionFunc Int32.TryParse x // A unique overload for method 'TryParse' could not be determined (...)
I tried many things and accidentally got it to work by writing it like this instead:
let Int32TryParse (x:string) =
x |> ToOptionFunc Int32.TryParse
I just don't understand why this compiles and the former does not.
In .NET Core, the Int32.TryParse
function has some extra overloads - it can parse either string
or ReadOnlySpan<char>
. The original code stopped working, because the compiler did not know which overload you wanted to use.
In the version without pipe, the compiler needs to type-check ToOptionFunc Int32.TryParse x
. It proceeds from left to right and when it gets to Int32.TryParse
, it does not yet know about x
(which has a type annotation constraining that to string
) and without knowing about x
, it cannot know which TryParse
you need.
In the version with pipe, the compiler needs to type-check x |> ToOptionFunc Int32.TryParse
. It proceeds from left to right and knows that x
is string
, so it then infers that the function passed to ToOptionFunc
must also be taking string
- and when it checks Int32.TryParse
, it can already uniquely determine the overload.
The summary is, pipe has very nice properties for guiding type-checking!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With