Zaid-Ajaj / Fable.Remoting

Type-safe communication layer (RPC-style) for F# featuring Fable and .NET Apps
https://zaid-ajaj.github.io/Fable.Remoting/
MIT License
273 stars 55 forks source link

Hard to use APIs due to lack of parameter names #100

Closed vasily-kirichenko closed 5 years ago

vasily-kirichenko commented 5 years ago

Do I understand rightly that the following API method is idiomatic?

image

If so, I find it very inconvenient to use because it lacks parameter names. The only way to improve it I could think about is adding a lot of type aliases, so it could look like this:

type Host = string
type App = string
type Op = string
PerformOp: Host * App * Op -> Async<unit>

Despite it looks nicely, adding the type aliases feels more like a hack around the language limitation.

Zaid-Ajaj commented 5 years ago

I would call an API idiomatic if it reflects your intent, which is not the case here. You have a couple of options:

// not just a type alias

type Host = Host of string
type App = App of string
type Operation = Operation of string

PerformOp: Host * App * Operation -> Async<unit>

then it would be clear what you want to send from the call site:

do! server.PerformOp (Host "myHost", App "myApp" , Operation "myOp") 

Or use record

type PerformOperationParams = { Host: string; App: string; Operation: string }
PerformOp : PerformOperationParams -> Async<unit>

or be more creative if you have optional parameters. although I wouldn't suggest this if you have many api's that look the same

type IPerformOp =
  | App of string
  | Host of string 
  | Operation of string

type PerformOp : IPerformOp list -> Async<unit> 

on call site

do! server.PerformOp [ App "myApp"; Host "myHost" ]  
Zaid-Ajaj commented 5 years ago

I believe this can be closed

vasily-kirichenko commented 5 years ago

@Zaid-Ajaj

Why interfaces are no allowed instead of records of functions? They would solve this problem very nicely and naturally.
Zaid-Ajaj commented 5 years ago

@vasily-kirichenko Interface meta data (member names, types of members) are not available at run-time (erased at compile-time) so it is a Fable limitation at first and second I prefer not have two ways of doing the same thing since record protocols work really well and I presented possible workarounds for your specific issue

vasily-kirichenko commented 5 years ago

Interface meta data (member names, types of members) are not available at run-time (erased at compile-time)

I'm pretty sure this meta data is presented in TAST. Does Fable transform TAST?

Zaid-Ajaj commented 5 years ago

Does Fable transform TAST?

AFAIK it does, however Fable translation is not 100% one-to-one from F# to javascript, if all of TAST were to be compiled, the bundle size of the generated javascript would inflate, therefore Fable only includes limited support for reflection and injects meta data of a handful of supported types adhoc when the type information is available at compile type. That said, adding support for inspecting interface metadata shouldn't be too difficult to do