Method Overloading in F#


In my goal to learn F# better, I’m doing all of my recreational development in the language. This gives me lots of learning opportunities (better known as WTF moments). I was implementing a MembershipProvider for an ASP.NET web site where the datastore is not SQL. By and large, MembershipProvider requires that you implement uniquely named methods. It does exposes a pair of abstract methods that one must implement. In C#, they look like this:

    public abstract MembershipUser GetUser(

        string username,

        bool userIsOnline);

 

    public abstract MembershipUser GetUser(

        Object providerUserKey,

        bool userIsOnline);

These two methods seemed pretty natural to overload in F#. I just wrote these stubs:

        override this.GetUser(providerUserKey: obj, userIsOnline: bool) : MembershipUser =

            null

 

        override this.GetUser(userName: string, userIsOnline: bool) : MembershipUser =

            null

The compiler didn’t like this, telling me

Duplicate definition of value 'AwsMembershipProvider.GetUser.3.override'

No amount of fiddling with the signature produced results. I was at a loss, so I pulled out the Object Browser in VisualStudio and focused on the FSharp.Core assembly. This looked like a job for a special attribute– F# seems to handle interop with the object oriented world via attributes and a few keywords. None of the keywords looked right. That’s when I found Microsoft.FSharp.Core.OverloadIDAttribute. Clicking on the class in the object browser, I learned this:

Adding the OverloadID attribute to a member permits it to be part of a group overloaded by the same name and arity. The string must be a unique name amongst those in the overload set. Overrides of this method, if permitted, must be given the same OverloadID, and the OverloadID must be specified in both signature and implementation files if signature files are used.

Now I got it– the overload didn’t work because both methods had the same arity (number of arguments). I needed to tell the compiler that these two methods looked the same, but have different IDs for the overload set. This is what got me to compile:

        [<OverloadID("GetUser.obj.bool")>]

        override this.GetUser(providerUserKey: obj, userIsOnline: bool) : MembershipUser =

            null

 

        [<OverloadID("GetUser.string.bool")>]

        override this.GetUser(userName: string, userIsOnline: bool) : MembershipUser =

            null

%d bloggers like this: