Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cannot resolve an F# method that has been both overridden and overloaded from C#

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?

like image 898
nxn Avatar asked Nov 23 '11 16:11

nxn


1 Answers

No doubt you're aware that if you omit the Test(x,y) member from the Descendant type -- or simply rename it Test2(x,y) -- then the C# code will compile and run as expected.

Looking at the IL generated for your original Descendant type offers a clue:

.method public hidebysig virtual
    instance int32 Test (
        int32 x
    ) cil managed ...

.method public 
    instance int32 Test (
        int32 x,
        int32 y
    ) cil managed ...

Notice that there's no hidebysig attribute on the Test(x,y) method.

The ECMA CLI specification has the following to say about hidebysig. (Section 15.4.2.2, emphasis in bold is mine.)

hidebysig is supplied for the use of tools and is ignored by the VES. It specifies that the declared method hides all methods of the base class types that have a matching method signature; when omitted, the method should hide all methods of the same name, regardless of the signature.

So, the F# compiler omits the hidebysig attribute, meaning that the Test(x,y) method hides all other methods named Test. Although hidebysig is 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.

like image 67
LukeH Avatar answered Nov 08 '22 20:11

LukeH