views:

112

answers:

2

I am interested in leveraging F#'s strengths in the area of parallelism into an existing .Net application. That is-I would like to factor in an F# component that would handle only the concurrent messaging of my application while leaving most of my existing .Net project as is. The existing app would call into the F# component.

1) Is this architecture advisable? 2) If so, are there any examples out there that demonstrate a best practices approach to this design?

Thanks,

John

+3  A: 

This is certainly a valid approach to the problem. It's really no different than factoring out any part of your application into a separate class library. Any best practices with this process should apply to the language of the new DLL being F#.

Shameless Self Promo Below:

If you're looking for real world examples that take this approach one project to look at is the VsVim project. It's a Vim emulator for Visual Studio which relies on F# for it's core functionality but uses C# to integrate into Visual Studio.

It may not contain all of the best practices but it does contain examples of working around some of the F# constructs which can be odd to use in languages like C# or VB.Net. In particular options and discriminated unions.

JaredPar
+3  A: 

1) Is this architecture advisable?

It certainly isn't a bad approach :)

The main thing I'd be worried about is how it affects other members of the team -- will they need to learn a new language to add new functionality or debug problems? If the rest of your team isn't comfortable using it, you might want to consider looking for or building your own message passing library in C#.

2) If so, are there any examples out there that demonstrate a best practices approach to this design?

I like to mix F# and C# in my projects all the time. In my own experience, leveraging C# dlls from F# is much easier than the other way around. Most of the constructs we like to use in F# look funny and unintuitive in C#. Just for funsies, see how the following code renders in Reflector:

let f x y z = x(y z)
let (|A|B|C|) x =
    match x with
    | 1 -> A
    | 2 -> B
    | x -> C x
type whatever = X | Y | Z of int

Curried functions render as an FSharpFunc, active patterns have a funny name and return type, unions have a very strange set of members, etc. They look weird in C#, so you'll very likely want to expose a facade with nicer C# signature for any modules you expect to be consumed publically. For example:

module CSharpFacade =
    let f(x : System.Func<_, _>, y : System.Func<_, _>, z) = f (fun param -> x.Invoke(param)) (fun param -> y.Invoke(param)) z

    [<AbstractClass>]
    type Whatever() =
        inherit obj()
        abstract member Map : unit -> whatever
    type X() =
        inherit Whatever()
        override this.Map() = whatever.X
    type Y() =
        inherit Whatever()
        override this.Map() = whatever.Y
    type Z(value : int) =
        inherit Whatever()
        member this.Value = value
        override this.Map() = whatever.Z(value)

So its pretty straight forward to wrap up F# delegates and unions for C#. I don't really care to expose the active pattern, its going to be internal unless otherwise needed.

And you might want to wrap Some/None types in something more palatable, such as using Nullable<someValueType> in place of Option<someValueType>, and mapping a null reference type to None where needed, etc.

Juliet
In general, avoid all F#-specific constructs at assembly boundaries when you want to consume F# assemblies from other languages.
Brian