RandomEngy / PipeMethodCalls

Lightweight .NET Standard 2.0 library for method calls over named pipes for IPC. Supports two-way communication with callbacks.
https://www.nuget.org/packages/PipeMethodCalls
MIT License
145 stars 24 forks source link

InvokeAsync hangs when using a function with > 1 argument in F# unless the args are tupled #12

Closed ordinaryorange closed 3 years ago

ordinaryorange commented 3 years ago

Was trying PipeMethodCalls in F#

An F# function handler with a single argument like this works use pipeServer = PipeServer (NetJsonPipeSerializer()) "mypipe" (fun a -> a) ... use pipeClient = new PipeClient<int->int>(NetJsonPipeSerializer(), "mypipe")

But the client will hang on InvokeAnync with this use pipeServer = PipeServer (NetJsonPipeSerializer()) "mypipe" (fun a b -> a+b) ... use pipeClient = new PipeClient<int->int->int>(NetJsonPipeSerializer(), "mypipe")

If I tuple the args, it works again. use pipeServer = PipeServer (NetJsonPipeSerializer()) "mypipe" (fun (a, b) -> a+b) ... use pipeClient = new PipeClient<(int*int)->int>(NetJsonPipeSerializer(), "mypipe")

The tuple is a workaround, but it would be nice for the former to work.

RandomEngy commented 3 years ago

I'm not very familiar with F# but it looks like you are passing in a function as the generic type parameter on PipeClient? That needs to be an interface type that represents which functions you can invoke.

ordinaryorange commented 3 years ago

I'm by no means an F# expert either. I did wonder if the way function composition works in F# that this means a function was being passed, but I don't think it is. Your lib does not actually need and interface, it works beautifully without. My working examples don't use any interfaces, just pure function signatures.

I tried this example.

use pipeServer = PipeServer myser "mypipe" System.String.Equals ...

use pipeClient = new PipeClient<string->string->bool>(myser, "mypipe")

let! result = pipeClient.InvokeAsync(fun x -> x "hi" "hi") |> Async.AwaitTask

which uses the Equals method as defined in the BCL as the function handler (which takes 2 args) and avoids any possible function composition issues.

This does not work, I get the following error The member or object constructor 'Equals' does not take 1 argument(s). An overload was found taking 2 arguments.

so it does look like a limitation by some subsystem that any function handler can only take 1 argument.

To be honest I have not tested a 2 arg func in C#, but I'd guess the same result. Not a big issue my end, and certainly not high on the priority list for a fix. Just thought I'd more mention it if you happen to know why and/or if it might be a simple fix.

Nice lib otherwise !

RandomEngy commented 3 years ago

I am honestly quite surprised that passing in a function type works at all. That third parameter to PipeServer is supposed to return an object with methods you can invoke remotely, as in the examples here: https://github.com/RandomEngy/PipeMethodCalls