GRPC - why does `CallInvoker` need to impose `TRequest: class` and `TResponse: class`?

Viewed 245

The signature defined by the abstract class CallInvoker in Grpc.Core imposes a type constraint class on both TRequest and TResponse. This prevents the use of structs as responses for the remote method, e.g. it doesn't work with F# result type Result<'a, 'b> as the response type, as F# Result<_, _> is a struct type.

Why does CallInvoker need to impose TRequest: class and TResponse: class?

https://github.com/grpc/grpc/blob/master/src/csharp/Grpc.Core.Api/CallInvoker.cs

1 Answers

I've looked at this in the past, as I wanted to propose removing it for protobuf-net.Grpc (which works fine with F#, btw); there's no fundamental reason, other than the code uses the sentinel null in many places to have meaning - and all of those scenarios would need changing, presumably to tuple-like type that encodes "has value" and "value" (essentially Nullable<T> but for any T); and that's quite a lot of work.

I'm open to giving it a try, though; it might actually be easier than the workaround I was planning for protobuf-net.Grpc (involving wrapping value-types on the fly).

For now, you'll have to use F# reference types. As an example, this work fine with protobuf-net.Grpc:

[<DataContract; CLIMutable>]
type MultiplyRequest =
    { [<DataMember(Order = 1)>] X : int
      [<DataMember(Order = 2)>] Y : int }

[<DataContract; CLIMutable>]
type MultiplyResult =
    { [<DataMember(Order = 1)>] Result : int }

[<ServiceContract(Name = "Hyper.Calculator")>]
type ICalculator =
    abstract MultiplyAsync : MultiplyRequest -> ValueTask<MultiplyResult>
Related