2

I can do this (F# FSI):

let o = Object()
let m = o.GetHashCode;; //[1]
val o : Object
val m : (unit -> int)

which makes method GetHashCode accessible and callable as a first-class function in binding m:

m ();;
val it : int = 12345678

How would I go about doing this if there existed an overload for the method in question, say an additional Object.GetHashCode(int whateverParameter)? I now can only get the 'first' (shortest?) method. Can I provide extra parameter type information in call 1 to specify which overload I desire?

EDIT

Thanks for your input so far. Type annotations seem the way to go. Albeit, for my more complicated example I still cannot figure out how to correctly do that.

Here are the concrete method signatures from the type I am dealing with (it comes from the octokit.net library, so you need something like #r "nuget:include=Octokit" in your fsi [with /langversion:preview]).

I am interested in retrieving a specific overload of GetAllForRepository, incidentally the first one listed: GetAllForRepository(string, string).

open Octokit
let client = GitHubClient(...)
client.Issue.GetType().GetMethods()
|> Seq.filter (fun methodInfo -> methodInfo.Name.StartsWith("GetAllForRepository"))
|> Seq.map (fun methodInfo -> (methodInfo.GetParameters(), methodInfo.ReturnType))
|> Seq.map (fun (parameterInfos, returnType) ->
    (parameterInfos |> Seq.map (fun parameterInfo -> parameterInfo.ParameterType.FullName), returnType.FullName))

val it : seq<seq<string> * string> =
  seq
    [(seq ["System.String"; "System.String"],
      "System.Threading.Tasks.Task`1[[System.Collections.Generic.IReadOnlyList`1[[Octokit.Issue, Octokit, Version=0.48.0.0, Culture=neutral, PublicKeyToken=null]], System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]");
     (seq ["System.Int64"],
      "System.Threading.Tasks.Task`1[[System.Collections.Generic.IReadOnlyList`1[[Octokit.Issue, Octokit, Version=0.48.0.0, Culture=neutral, PublicKeyToken=null]], System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]");
     (seq ["System.String"; "System.String"; "Octokit.ApiOptions"],
      "System.Threading.Tasks.Task`1[[System.Collections.Generic.IReadOnlyList`1[[Octokit.Issue, Octokit, Version=0.48.0.0, Culture=neutral, PublicKeyToken=null]], System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]");
     (seq ["System.Int64"; "Octokit.ApiOptions"],
      "System.Threading.Tasks.Task`1[[System.Collections.Generic.IReadOnlyList`1[[Octokit.Issue, Octokit, Version=0.48.0.0, Culture=neutral, PublicKeyToken=null]], System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]");
     (seq ["System.String"; "System.String"; "Octokit.RepositoryIssueRequest"],
      "System.Threading.Tasks.Task`1[[System.Collections.Generic.IReadOnlyList`1[[Octokit.Issue, Octokit, Version=0.48.0.0, Culture=neutral, PublicKeyToken=null]], System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]");
     (seq ["System.Int64"; "Octokit.RepositoryIssueRequest"],
      "System.Threading.Tasks.Task`1[[System.Collections.Generic.IReadOnlyList`1[[Octokit.Issue, Octokit, Version=0.48.0.0, Culture=neutral, PublicKeyToken=null]], System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]");
     (seq
        ["System.String"; "System.String"; "Octokit.RepositoryIssueRequest";
         "Octokit.ApiOptions"],
      "System.Threading.Tasks.Task`1[[System.Collections.Generic.IReadOnlyList`1[[Octokit.Issue, Octokit, Version=0.48.0.0, Culture=neutral, PublicKeyToken=null]], System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]");
     (seq
        ["System.Int64"; "Octokit.RepositoryIssueRequest";
         "Octokit.ApiOptions"],
      "System.Threading.Tasks.Task`1[[System.Collections.Generic.IReadOnlyList`1[[Octokit.Issue, Octokit, Version=0.48.0.0, Culture=neutral, PublicKeyToken=null]], System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]")]

Now, the 'shortest' signature takes one int64 parameter:

let m = client.Issue.GetAllForRepository;;
val m :
  (int64 ->
     System.Threading.Tasks.Task<System.Collections.Generic.IReadOnlyList<Octokit.Issue>>)

I can explicitly declare the signature and receive the same method:

let m: (int64 -> System.Threading.Tasks.Task<System.Collections.Generic.IReadOnlyList<Octokit.Issue>>) = client.Issue.GetAllForRepository;;
val m :
  (int64 ->
     System.Threading.Tasks.Task<System.Collections.Generic.IReadOnlyList<Octokit.Issue>>)

But accessing the (string, string) version gives me:

let m: (string -> string -> System.Threading.Tasks.Task<System.Collections.Generic.IReadOnlyList<Octokit.Issue>>) = client.Issue.GetAllForRepository;;

  let m: (string -> string -> System.Threading.Tasks.Task<System.Collections.Generic.IReadOnlyList<Octokit.Issue>>) = client.Issue.GetAllForRepository;;
  --------------------------------------------------------------------------------------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stdin(33,117): error FS0193: Type constraint mismatch. The type
    'string'
is not compatible with type
    'int64'

Similar error occur when trying to access any other overload with more than one parameter:

let m: (int64 -> Octokit.RepositoryIssueRequest -> System.Threading.Tasks.Task<System.Collections.Generic.IReadOnlyList<Octokit.Issue>>) = client.Issue.GetAllForRepository;;

  let m: (int64 -> Octokit.RepositoryIssueRequest -> System.Threading.Tasks.Task<System.Collections.Generic.IReadOnlyList<Octokit.Issue>>) = client.Issue.GetAllForRepository;;
  -------------------------------------------------------------------------------------------------------------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stdin(37,140): error FS0001: This expression was expected to have type
    'Octokit.RepositoryIssueRequest -> System.Threading.Tasks.Task<System.Collections.Generic.IReadOnlyList<Octokit.Issue>>'
but here has type
    'System.Threading.Tasks.Task<System.Collections.Generic.IReadOnlyList<Octokit.Issue>>'
let m: (int64 -> Octokit.RepositoryIssueRequest -> Octokit.ApiOptions -> System.Threading.Tasks.Task<System.Collections.Generic.IReadOnlyList<Octokit.Issue>>) = client.Issue.- GetAllForRepository;;

  let m: (int64 -> Octokit.RepositoryIssueRequest -> Octokit.ApiOptions -> System.Threading.Tasks.Task<System.Collections.Generic.IReadOnlyList<Octokit.Issue>>) = client.Issue.GetAllForRepository;;
  -----------------------------------------------------------------------------------------------------------------------------------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stdin(36,162): error FS0001: This expression was expected to have type
    'Octokit.RepositoryIssueRequest -> Octokit.ApiOptions -> System.Threading.Tasks.Task<System.Collections.Generic.IReadOnlyList<Octokit.Issue>>'
but here has type
    'System.Threading.Tasks.Task<System.Collections.Generic.IReadOnlyList<Octokit.Issue>>'

So, am I doing something wrong with regard to the type annotations?

7enderhead
  • 71
  • 4
  • When I try to assign a method with an overload to a variable I get the suggestion *"A type annotation may be needed."* - did you try doing just that? – UnholySheep Jan 11 '21 at 12:47
  • @Christian Welcome to the F# community! – Scott Hutchinson Jan 11 '21 at 17:08
  • This indeed works for simple cases, like `let m: char -> int = "Hello".IndexOf;;`, chosing `System.String.IndexOf(char)` over `System.String.IndexOf(string)`. But the signatures of my intended methods (from the octokit.net library) are more complicated, like `Task> GetAllForRepository(string owner, string name)`. Perhaps it's due to the `Task<...>` return value. – 7enderhead Jan 11 '21 at 19:00
  • Have you tried `m: ((string * string) -> System.Threading.Tasks.Task>)`? – Mark Pattison Jan 13 '21 at 16:17

2 Answers2

3

Yes, a type annotation will allow you to select the method override that you want:

type MyClass() =
    member __.MyMethod() = 1
    member __.MyMethod(x : int) = 2

let o = MyClass()
let m1 : (unit -> int) = o.MyMethod
let m2 : (int -> int) = o.MyMethod
printfn "%A" <| m1 ()
printfn "%A" <| m2 0
Brian Berns
  • 15,499
  • 2
  • 30
  • 40
  • Thanks @brianberns. This works for 'simple' cases, unfortunately not for my real-world example. I have expanded the original question. – 7enderhead Jan 13 '21 at 16:09
1

In response to your edit, the method's input is string * string, not string -> string (i.e. uncurried vs. curried), so I think this will work:

let m : (string * string -> _) = client.Issue.GetAllForRepository
Brian Berns
  • 15,499
  • 2
  • 30
  • 40