Skip to content

Discussion: Improve C# to F# interoperability #1254

@eiriktsarpalis

Description

@eiriktsarpalis

I'm starting this issue to discuss potential changes that could improve C# to F# interoperability.
F# to C# interoperability works fine, but anyone who's ever used an F# library API from C# might have come across some of the following issues:

Optional parameters

Adding optional parameters to F# methods:

type Foo =
    static member Bar(?x : int) = ...

introduces an implicit dependency on F# option types:

using Microsoft.FSharp.Core;

Foo.Bar(x: FSharpOption<int>.None); // use default parameter
Foo.Bar(x: FSharpOption<int>.Some(42)); // override the parameter

this can be extremely off-putting for a non-F# user, and it gets worse as the number of optional parameters increases. The situation can be somewhat improved using this technique, but it still is a tedious exercise to decorate all possible optional parameters in your public api with proper attributes. Even if this is done correctly, overridden parameters would still have to be wrapped in Some.

Here are a few potential fixes:

  • Have the F# compiler automatically attach the Optional and DefaultValue attributes to every optional parameter it encounters. I believe that this does not introduce any backward compatibility issues.
  • Implement a "CompatibleOptional" attribute to be attached to arguments and/or method definitions. This would tell the F# compiler to attach the Optional and DefaultValue attributes to the parameters and potentially expose the parameters in a non-F# option representation: perhaps nullable for value types and null for classes.
  • We could perhaps sweeten the pill without making radical changes: add an FSharp.Compat namespace in FSharp.Core which implements helper methods for easily creating/wrapping values in F# option. Here's an example of how it could be done.

Lambda parameters

Public F# APIs that expose lambda parameters are virtually impossible to consume from other languages: users have to explicitly define a class that inherits FSharpFunc<_,_> which is extremely prohibitive.

Here are a few potential solutions:

  • Add an FSharp.Compat namespace in FSharp.Core which implements helper methods for wrapping common delegate types in F# functions. Here's an example of how it could be done.
  • Might be too far-fetched, but perhaps we could convince the roslyn team have lambda literals target F# funcs?

Conclusion

Please add any other interop issues that you might have come across. I firmly believe that the aforementioned issues seriously hurt widespread .NET adoption of good F# libraries. We can do much better than that.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions