OO alternative to polymorphism in F # when calling F # from C #

I want to create a library that will create objects using a user-defined function and modify them using another user-defined function.

I have an OCaml background and see a pretty simple way to implement it:

//user side type userType = { mutable time : float } let userInitialization () = { time = 0. } let userModification t = t.time <- t.time+1. //my side let algo initialization modification n = let a = Array.init n (fun _ -> initialization ()) modification a.[0] a 

The problem is that I want this library to be easily called from C #: having functions as arguments is probably bad ideas.

The interface and the abstract class (which userType inherits from) seems to be a normal OO solution, but I cannot initialize the object if I don't know the (not yet defined) userType taking the initialization step, inside my function is impossible.

The only workaround I can think of is to ask the user to instantiate their userType as an argument, which will be used to call initialization, but this seems very inelegant.

Is there any way to solve this problem?

+7
c # oop f #
source share
2 answers

You can define an interface like this:

 type IInitAndModify<'T> = abstract member CreateNew : unit -> 'T abstract member Modify : item : 'T -> unit 

and possibly also an object that the user can use to pass it to your implementation:

 type Algo<'T> () = member this.Execute (initAndModify : IInitAndModify<'T>, n) = algo initAndModify.CreateNew initAndModify.Modify n 

From C #, it looks like this:

 public interface IInitAndModify<T> { T CreateNew(); void Modify(T item); } public class Algo<T> { public Algo(); public T[] Execute(IInitAndModify<T> initAndModify, int n); } 

The development client can use it as follows:

 public class UserType { public float Time { get; set; } } public class UserInitAndModify : IInitAndModify<UserType> { public UserType CreateNew() { return new UserType { Time = 0 }; } public void Modify(UserType item) { item.Time++; } } 

and write this program:

 static void Main(string[] args) { var a = new Algo<UserType>(); var values = a.Execute(new UserInitAndModify(), 10); foreach (var v in values) Console.WriteLine(v.Time); } 

When you run the above Main method, the output is as follows:

 1 0 0 0 0 0 0 0 0 0 Press any key to continue . . . 
+5
source share

I would be inclined to reject the idea that you should not expose functions as arguments in a library exposed to C #, and this is becoming quite common, you only need to take a look at LINQ, TPL, etc. I don’t think that too many C # developers will be scared by this.

I would, however, suggest that you avoid exposing career functions to C # arguments, since they are generally not convenient to use.

You can pretty easily wrap your algorithm in a function that takes arguments in a form by form and provides System.Func and System.Action for C #.

 let csAlgo (initialisationFunc : System.Func<'a>, modificationFunc : System.Action<'a>, n : int) = algo (initialisationFunc.Invoke) (modificationFunc.Invoke) n 

in C # you could do this:

 var res = Module.csAlgo(() => new UserType(0), t => t.Time = t.Time + 1, 16); 

You can also use the CompiledName attribute as a small span so that you can get your legend in each language. Mark your function

 [<CompiledName("ExampleFunction")>] let exampleFunction () = 1 

Then in C # it looks like this:

 var num = Module.ExampleFunction(); 
+5
source share

All Articles