The case is a bit confusing because when you use an array as the actual argument for a parameter marked with a ParamArray , the language tries to interpret it as if you were passing the array to standard typed parameters of the array (therefore, it ignores the ParamArray attribute, if possible).
In your example, this is possible in the second case:
Generic.Echo [|0|]
The compiler reports that 'T is int , and therefore you pass int[] parameter of type int[] , and therefore the compiler ignores the ParamArray attribute, and the method simply gets an array containing 0 .
Otherwise, this is not possible:
Heterogeneous.Echo [|0|]
The method expects a parameter of type obj[] , and the argument type is int[] , so the two types cannot be unified (the key is that the compiler does not automatically convert int[] to obj[] ), since this is impossible, it considers the ParamArray attribute and trying to convert int[] to obj and pass it as a member of ParamArray - this is a conversion that the compiler can automatically perform, and therefore you get the result that you described.
If you called Heterogeneous.Echo with obj[] as an argument, it will behave similarly to Generic.Echo . For instance:
Heterogeneous.Echo [| box 0 |]
If you want to go into details, you can see section 14.4. F # language specification . However, the rules for overload resolution are quite complex, so I don't have an exact link that explains this behavior - just an unofficial explanation above.
source share