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:
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:
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:
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.
This seems a noble cause.
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.
Wouldn't this break existing C# to F# 'interopers'? If someone has explicitly passed in a FSharpOption<int> from C#, and these attributes are added, wouldn't that be breakage?
The function now expects (from C#) an int or nothing, but gets an option.
@rojepp the attributes do not change the method's signature, they merely allow for optional attributes to be omitted. If somebody passed all arguments in correct order, it would still work as before.
@eiriktsarpalis I think this could made directly into an RFC - doing work in this area would be great.
There may also be a set of op_Implicit or op_Explicit conversions that can help things from C#?
@dsyme Implicit converters are enticing, however it looks like they do not work well with lambda literals. Using the System.Converter implicit converter we see that
Converter<int, int> func = x => x + 1;
FSharpFunc<int, int> fsfunc = func;
works as expected, however
FSharpFunc<int, int> func = x => x + 1;
complains with
(1,29): error CS1660: Cannot convert lambda expression to type 'FSharpFunc<int, int>' because it is not a delegate type
@eiriktsarpalis Yeah it would be ideal if that worked. Perhaps add a Roslyn issue about it - Mads might actually do this.
BTW is that with adding actual op_Implicit definitions to the FSharpFunc type?
@eiriktsarpalis Oh yes, I forgot we had those already.
@dsyme So you're saying we should ask the roslyn guys to enable implicit conversions for lambda literals? Or just support F# funcs?
Btw, I just picked up from the internets that this also works but it looks a bit confusing:
FSharpFunc<int, int> func = (Converter<int,int>)(x => x + 1);
@eiriktsarpalis It would be up to the C# designers. This may be one instance of a more general problem they are encountering elsewhere (i.e. things that are lambda-like but aren't delegates).
@eiriktsarpalis Of course preparing a PR to roslyn would help enormously.
Maybe single method interfaces like Java 8 has ;-)
From: Don Symemailto:[email protected]
Sent: ‎10/‎06/‎2016 17:36
To: Microsoft/visualfsharpmailto:[email protected]
Subject: Re: [Microsoft/visualfsharp] Discussion: Improve C# to F# interoperability (#1254)
@eiriktsarpalis It would be up to the C# designers. This may be one instance of a more general problem they are encountering elsewhere (i.e. things that are lambda-like but aren't delegates).
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/Microsoft/visualfsharp/issues/1254#issuecomment-225216594
It would be nice to have [<Extension>] added automatically to a class/module if it contains a member with it defined. And it also should define it automatically on the assembly otherwise VB.NET won't find the extension methods.
Support an [<CompiledNameConvention(CompiledNameConventions.TitleCasePublicMembers)>] attribute on module definition to make [<CompiledName("MyFunction")>] boilerplate go away while retaining C#/VB.NET friendly naming conventions and keeping the nice names in F#.
There's an existing uservoice about the first option: https://fslang.uservoice.com/forums/245727-f-language/suggestions/5663298-improve-optional-parameter-interop-between-f-and
Having added 145! [<Optional>] attributes on FSharp.Data, I would really welcome if they were auto added :)
I'd really like to see progress on the optional attributes issue, perhaps in time for F# 4.1 (though the window is closing rapidly on that, partly because there's a considerable amount of other non-language work to get through in https://github.com/Microsoft/visualfsharp). I don't yet think I can prioritize it fo myself, though would welcome someone else fleshing out an RFC.
Another possibility is adding an implicit converter to FSharpOption:
type Option<'T> with
static member op_Implicit : 'T -> 'T option
Note that implicit converters can only be placed at the type definition and do not work when extension methods. I tried it out with a custom build of FSharp.Core and here are the results:

Seems to be working nicely. If we additionally have the F# compiler automatically append the optional/default attributes to optional parameters, we will have practically solved the optional parameter interop issue. My understanding is that the presence of op_Implicit will not affect any existing F# code.
My understanding is that the presence of op_Implicit will not affect any existing F# code.
That's correct. It might be interesting to do this for FSharpAsync<T> (from Task) and even FSharpList<T> (from IEnumerable)
@dsyme I think though that those conversions might be dangerous since the first one entails potential side-effects and the latter might cause problems if the IEnumerable is large or infinite.
EDIT: Actually, scratch that first one, I read it in the opposite :)
Surely it would only go one way i.e. FSharpList -> IEnumerable, and not the other way around?
Pardon my ignorance, but what would it take for C# async to be able to return FSharpAsync<T/Unit> ?
@isaacabraham they're already in a subtype relationship so this shouldn't be an issue.
@smoothdeveloper C# computation expressions :-) Actually, there's a new Roslyn feature under way that might do just that. Look up the new ValueTask feature for more details.
@dsyme I'd love to see optional parameter enhancements find their way in F# 4.1. I could create a PR.
@eiriktsarpalis except as you said, IEnumerable is lazy whereas List isn't - the latter can safely go into the former but not the other way around?
@isaacabraham It's potentially lazy. Lists, arrays and collections are instances of IEnumerable that are materialized whereas a state machine that produces infinite streams could be considered lazy.
About lambda parameters:
When adding delegate overloads to previously FSharpFunc methods by hand, sadly it can be a breaking change in existing F# code. Implicit conversion from F# lambda to delegate causes an ambigous overload. Similarly with quoted versions:
open System
open FSharp.Quotations
open System.Linq
open System.Linq.Expressions
type T() =
member this.X(f: int -> int) = 0
member this.X([<ReflectedDefinition>] f: Expr<int -> int>) = 1
member this.X(f: Func<int,int>) = 2
member this.X(f: Expression<Func<int,int>>) = 3
T().X(fun x -> x) // having any two overloads results in error
When removing the FSharpFunc overload (keeping only delegate version), that is breaking previous code that passes a function value instead of a lambda (we chose this).
If no other solution is implemented, it would be nice to at least have a priority resolution here, no errors if only one overload is found in the highest category, priority from highest to lowest:
If there are multiple parameters, it could use the one with the highest category.
(Should I move this proposal to uservoice or separate issue?)
That compiled name attribute was also discussed on fable. I think it would be super useful. /cc @alfonsogarciacaro
This is another thing which I find upsetting trying to use option from C# need to have this defined: http://www.fssnip.net/so/title/Make-option-type-usable-in-C
All types from FSharp.Core should be reviewed to make their use easy from C#.
would be very nice to turn FSharp.Options into nullables from a Record with compiler attributes from from F# side, or when marked with [
Closing old discussion
Most helpful comment
Another possibility is adding an implicit converter to FSharpOption:
Note that implicit converters can only be placed at the type definition and do not work when extension methods. I tried it out with a custom build of FSharp.Core and here are the results:

Seems to be working nicely. If we additionally have the F# compiler automatically append the optional/default attributes to optional parameters, we will have practically solved the optional parameter interop issue. My understanding is that the presence of
op_Implicitwill not affect any existing F# code.