I've read many times that
Assemblies generated from F# or any other .NET language are (almost) indistinguishable.
I was then experimenting with F# and C# interop on .NET 4 (beta 2). I created a new solution, and a C# project, with the following class:
public class MyClass {
public static int Add(int a, int b) { return a + b; }
}
Then, on a F# project, after referencing the C# project, I tried:
MyClsas.Add(4, 5) |> printfn "%d" // prints 9 (no kidding!)
So far so good. Then another sentence I've read many times (perhaps on different books) came to my mind:
When passing arguments to functions from other .NET libraries, you use a syntax like ".MethodName(parm1, parm2)", that is, the parameters are passed as a Tuple.
Add that to something that I've once read here on SO (but wasn't able find it to link to), on a question where the OP was trying to create a using like [ 4, 5, 6 ]
(when he meant [4; 5; 6]
):
"Comma is the 'tuple creating operator', for everything else use semi-colon."
Then I modified my class to the following:
public class MyClass {
public static int Add(int a, int b) { return a + b; }
public static int Add(Tuple<int, int> a) { return a.Item1; }
}
Now I tried to use it on F#:
MyClass.Add(4, 5) |> printf "%d" // prints ... (keep reading!)
So, adding up the three quotations above, one can conclude that:
- F# will create a Tuple when it sees
(4, 5)
- Then it will call the overload
Add(Tuple<int, int>)
- So it will print 4
To my surprise, it printed 9. Isn't it interesting?
What is really happening here? The above quotations and this practical observations seems to be in contradiction. Can you justify F#'s "reasoning", and maybe pointing to some MSDN docs if possible?
Thanks!
EDIT
(to add more information (from Blindy's answer))
If you do:
MyClass.Add((4, 5)) |> printfn "%d" // prints 9
F# calls the Add(Tuple<int, int>)
overload.
However, if you create another F# project (so a different assembly) with this:
namespace MyFSharpNamespace
type MyFShapClass = class
static member Add x y = x + y
end
You can use it on C# like this
public static void Main(string[] args) {
MyFSharpNamespace.MyFSharpClass.Add(4, 5);
}
So far so good. Now, when you try to use it from F# (from another project, another assembly), you have to do:
MyFSharpNamespace.MyFSharpClass.Add 4 5 |> printfn "%d"
If you pass the arguments as (4, 5)
F# will not compile because Add
is int -> int -> int
, and not (int * int) -> int
.
What is happening?!?