Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overload resolution with TryParse

Tags:

f#

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.

like image 296
Asik Avatar asked Mar 13 '19 20:03

Asik


1 Answers

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!

like image 104
Tomas Petricek Avatar answered Nov 04 '22 20:11

Tomas Petricek