views:

133

answers:

2

I was trying to use Rhino Mocks with F# code, and the following code was a problematic:

let service = MockRepository.GenerateMock<IMyService>()
service.Stub(s => s.Name).Return("Service");

This was no surprise, since Stub is not part of IMyService interface, it's a C# extension method that Rhino Mocks defines.

Slighltly modified code works:

let service = MockRepository.GenerateMock<IMyService>()
RhinoMocksExtensions.Stub<IMyService, string>(service, fun s -> s.Name).Return("Service");

However, it would be nice to define an extension method in F#, but then it will be a parameterized generic extension method that would take a tuple . I was trying varios syntax but without any luck. I didn't find information whether this is currently supported in F# or not. If anyone knows, please let me know.

+3  A: 

If I understand your question correctly, the answer is no. Section 8.12.1 of the spec (Imported C# Extensions Members) includes this text:

C#-defined extension members are made available to F# code in environments where the C#-authored assembly is referenced and an open declaration of the corresponding namespace is in effect. However, some limitations apply, notably

  • C# extension members whose “this” parameter is a variable type are not made available to F# code in this version of F#

  • C# extension members whose “this” parameter is an array type are not made available to F# code in this version of F#

This explains why some extension methods from C# will work (e.g. those in System.Linq), while the one that you are attempting to use will not.

Furthermore, native F# extension methods can only be defined as if they were placed on actual type definitions. In particular, you can't define an F# extension method on a closed generic type (e.g. IEnumerable<string>) nor can you define an extension method on a generic type variable.

kvb
Thank you for the answer!
Vagif Abilov
+4  A: 

As kvb mentioned, it's not possible in F# 2.0. In this particular case I'd wrap Rhino.Mocks fluent interface to make it more idiomatic in F#, e.g.:

let mstub f target =
    RhinoMocksExtensions.Stub(target, Function(f))

let mreturn value (options: IMethodOptions<'a>) =
    options.Return value

let service = MockRepository.GenerateMock<IComparer>()
service |> mstub (fun s -> s.Compare(1,2)) |> mreturn 1 |> ignore

What's fluent in one language is not necessarily fluent in another. (sorry for the plug but I really think it's relevant here)

Mauricio Scheffer
Marurcio,Thank you for the explanation. Yes, I also came to the same conclusion that such extensions that are quite useful in C# wouldn't bring that much value to F#, and there are other (and better) ways of expressing this in F#.
Vagif Abilov