The following F# code declares base and descendant classes. The base class has a virtual method ‘Test’ with a default implementaion. The descendant class overrides the base class method and also adds a new overloaded ‘Test’ method. This code compiles fine and presents no issues when accessing either of the descendant ‘Test’ methods.
F# Code:
module OverrideTest
[<AbstractClass>]
type Base() =
abstract member Test : int -> int
default this.Test x = x + 1
type Descendant() =
inherit Base()
override this.Test x = x - 1
member this.Test (x, y) = x - y
However, attempting to invoke the descendant’s override of ‘Test’ from C# results in a compilation error:
var result = td.Test(3); <- No overload for method ‘Test’ takes 1 arguments
The full C# Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Client
{
class Program
{
static void Main(string[] args)
{
var td = new OverrideTest.Descendant();
var result = td.Test(3);
Console.WriteLine(result);
Console.ReadKey();
}
}
}
The strange thing is that VisualStudio’s intellisense sees the two overloaded functions, and provides correct signatures for both. It gives no warnings or errors before the build fails, and only highlights the line afterwards.
I have re-implemented this scenario fully in C# and did not run into the same problem.
Anyone have any ideas what’s going on here?
No doubt you’re aware that if you omit the
Test(x,y)member from theDescendanttype — or simply rename itTest2(x,y)— then the C# code will compile and run as expected.Looking at the IL generated for your original
Descendanttype offers a clue:Notice that there’s no
hidebysigattribute on theTest(x,y)method.The ECMA CLI specification has the following to say about
hidebysig. (Section 15.4.2.2, emphasis in bold is mine.)So, the F# compiler omits the
hidebysigattribute, meaning that theTest(x,y)method hides all other methods namedTest. Althoughhidebysigis only “for the use of tools”, it appears that the C# compiler is one of those tools that uses it!This looks to me like it could be a bug in the F# compiler, but since I’ve never looked at the F# spec it’s always possible that this is allowed/specified behaviour.