Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Call an F# ticked function name with embedded spaces (``XXX YY``) from C#

Tags:

c#

f#

c#-to-f#

In F#, we can create a function like this:

let ``add x and y`` x y = x + y

And I can call it normally like this:

``add x and y`` 1 2

Is there a way to call the function above from C# side? I couldn't even see it in Object Browser though.

like image 574
kimsk Avatar asked Oct 11 '13 21:10

kimsk


People also ask

What is the meaning of the idiom call for?

Definition. Idiom: call for (something) to demand or require something.

How do you use called for?

call for something to publicly ask for something to happen They called for the immediate release of the hostages. The opposition party has called for him to resign.

What does it mean to call for someone?

(call for someone/something) to go somewhere and get someone or something in order to take them to another place.

What do you mean by called off?

verb (tr, adverb) to cancel or abandonthe game was called off because of rain. to order (an animal or person) to desist or summon awaythe man called off his dog. to stop (something) or give the order to stop.


2 Answers

You can expose any valid F# function name to C# as any C# valid function name using CompiledName attribute:

namespace Library1
module Test = 
    [<CompiledName("Whatever")>]
    let ``add a and b`` x y = x + y

and then in C#:

 using Library1;
 ...............
 System.Console.WriteLine(Test.Whatever(2,2));

FOLLOW-UP 03/05/2016 on comment from NickL, applies at least to F#3.1:

Moving from functions to members brings some "ifs and buts".

To begin with, CompiledName attribute does not compile with member if being used from pure namespace. The mere compilation requires use within a module.

When being used within a module and decorating method member of F# record it works just fine regardless of how the contents between two ticks looks. However when decorating property member of F# record CompiledName is visible cross-assembly only if contents between double ticks resembles some legal value name:

module M

type MyRecord =
    { myField: string }
    [<CompiledName "Whatever">]
    member x.``Blah Blah blah``() = x.myField
    [<CompiledName "Another">]
    member x.``ABC`` = x.myField

and then from C# the following works OK:

var recInC = new M.MyRecord("Testing...");
Console.WriteLine(recInC.Whatever());
Console.WriteLine(recInC.Another);

Such inconsistencies prompt for potential issues.

like image 155
Gene Belitski Avatar answered Oct 10 '22 14:10

Gene Belitski


Reflection might be the only way, but it doesn't have to be ugly to use. Just wrap it all within a class to do the reflecting.

public static class MyModuleWrapper
{
    // it would be easier to create a delegate once and reuse it
    private static Lazy<Func<int, int, int>> addXAndY = new Lazy<Func<int, int, int>>(() =>
        (Func<int, int, int>)Delegate.CreateDelegate(typeof(Func<int, int, int>), typeof(MyModule).GetMethod("add x and y"))
    );
    public static int AddXAndY(int x, int y)
    {
        return addXAndY.Value(x, y);
    }

    // pass other methods through.
    public static int OtherMethod(int x, int y)
    {
        return MyModule.OtherMethod(x, y);
    }
}

Then use it like normal.

var sum = MyModuleWrapper.AddXAndY(1, 2);
var otherValue = MyModuleWrapper.OtherMethod(1, 2); // use the wrapper instead

I'm not sure what needs to be changed or how if there are polymorphic types involved, but hopefully you get the idea and can apply the necessary changes.

like image 26
Jeff Mercado Avatar answered Oct 10 '22 14:10

Jeff Mercado